Why Push Business Rules Into Your SQL Server Schema, Not Just the App

Why Push Business Rules Into Your SQL Server Schema, Not Just the App

Constraints aren’t just data hygiene — they’re how you encode real business rules directly into the schema, so they can never be silently bypassed by a buggy application, a second app added later that talks to the same database, or a stray ad-hoc UPDATE run during an incident.

Who Actually Enforces This Rule?(app-only validation vs. schema-level)Web App Formvalidates on submitAdmin Scriptno UI validation here!Bulk Import Jobwritten by someone elsedbo.CustomerOrderorder_date DATE NOT NULLship_date DATE NULLCHECK (ship_date >= order_date)one rule, enforced for EVERY writerINSERT ship_date = order_date+3passes the CHECK — acceptedINSERT ship_date = order_date-5shipped before it was orderedCHECK constraint blocks itGotcha: app-only validation is bypassed by a second app,an admin script, or a direct fix during an incident.The CHECK constraint is the only one with zero gaps.

Encoding a Real Rule

-- Rule: an order's ship date can never be before its order date
CREATE TABLE dbo.CustomerOrder (
    order_id    INT IDENTITY(1,1) PRIMARY KEY,
    order_date  DATE NOT NULL,
    ship_date   DATE NULL
        CHECK (ship_date IS NULL OR ship_date >= order_date),
    total_usd   DECIMAL(10,2) NOT NULL CHECK (total_usd >= 0)
);
-- Proving the rule holds, not just reading about it:
INSERT INTO dbo.CustomerOrder (order_date, ship_date, total_usd) VALUES ('2026-01-10', '2026-01-05', 49.99);
-- Error: CHECK constraint violated — shipped 5 days BEFORE it was ordered, correctly rejected

A CHECK Constraint Spanning Multiple Columns

CHECK isn’t limited to validating one column against a literal — it can compare columns on the same row to each other, as shown above (ship_date against order_date). Another common shape:

CREATE TABLE dbo.Promotion (
    promotion_id  INT IDENTITY(1,1) PRIMARY KEY,
    starts_on     DATE NOT NULL,
    ends_on       DATE NOT NULL,
    CHECK (ends_on > starts_on)
);

This kind of cross-column rule is exactly the class of business logic that’s easy to forget to validate in one code path of an application (a bulk-import script, an admin panel, an API endpoint added six months later by someone unfamiliar with the original rule) but structurally impossible to skip once it lives in the schema.

The Last Line of Defense

App-only validation Bypassed by bugs, other apps, or a direct DB script during an incident Database constraint Enforced no matter what wrote the data — no gaps, no exceptions

Applications get replaced, have bugs, or get bypassed by a direct database script during an incident. A CHECK constraint at the database layer is enforced no matter what wrote the data — it’s the guarantee application code alone can never fully provide. This is sometimes summarized as “defense in depth”: validate in the application for a fast, friendly error message to the user, and validate in the database as the guarantee that actually holds under all circumstances.

Where This Doesn’t Reach — And What Does

CHECK constraints are limited to logic expressible within a single row’s own columns — they can’t reference other tables or aggregate across rows. “A department can’t have more than 20 staff” or “an order’s total must match the sum of its line items” needs a different tool: a trigger, or logic in a stored procedure. That’s a deliberate scope boundary you’ll meet by name (constraints vs. triggers vs. procedures) as a full decision framework in SQL Server for Developers & DBAs — for now, the key lesson is simply that single-row rules belong in CHECK constraints, full stop, because nothing enforces them more reliably.

Practice tip: Look at any form you’ve filled out recently (a signup form, a checkout flow) and identify one validation rule it enforces. Ask yourself: is that rule also enforced at the database level, or only in that one form? If you can imagine a second way data could enter that table — an admin tool, a script, a different app — that’s exactly the gap a CHECK constraint closes.

Enjoyed this?

Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

📡 Subscribe via RSS  | 
Share on X  | 
Share on LinkedIn  | 
Share on Facebook

Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server Fundamentals, coming soon on this site.