Tag: Computed Columns

  • Computed Columns and Multi-Column CHECK Constraints in SQL Server

    Computed Columns and Multi-Column CHECK Constraints in SQL Server

    CHECK constraints get genuinely powerful once they can reference multiple columns in the same row — exactly the boundary the previous lesson drew — and computed columns let you derive values automatically instead of trusting every INSERT/UPDATE to calculate them correctly and consistently.

    Computed Columns: Derived, Not Writtencheck_inDATE columncheck_outDATE columnnightly_rateDECIMAL, CHECK > 0nightsAS DATEDIFF(day,in,out)🔒 auto-derived, read-onlytotal_costAS nights * nightly_rate🔒 PERSISTED, indexableCHECK(check_out > check_in)

    A Table Using Both

    CREATE TABLE dbo.Booking (
        booking_id  INT IDENTITY(1,1) PRIMARY KEY,
        check_in    DATE NOT NULL,
        check_out   DATE NOT NULL,
        nightly_rate DECIMAL(8,2) NOT NULL CHECK (nightly_rate > 0),
        nights      AS DATEDIFF(DAY, check_in, check_out),
        total_cost  AS (DATEDIFF(DAY, check_in, check_out) * nightly_rate) PERSISTED,
        CONSTRAINT CK_Booking_Dates CHECK (check_out > check_in)
    );
    
    INSERT INTO dbo.Booking (check_in, check_out, nightly_rate) VALUES ('2024-06-01', '2024-06-05', 150.00);
    SELECT booking_id, nights, total_cost FROM dbo.Booking;

    Notice nights and total_cost are never written to directly — you can’t INSERT a value into them, and SQL Server rejects the attempt if you try. They’re recalculated automatically from check_in, check_out, and nightly_rate every time those source columns change, which structurally guarantees they can never drift out of sync the way a manually-maintained “total” column could.

    PERSISTED: Store It or Compute It Live?

    Not PERSISTED Recalculated on every SELECT Cannot be indexed PERSISTED Stored on disk, auto-synced Can be indexed

    Worthwhile when the column is read often relative to how often source columns change — total_cost on a booking is a good candidate, since it’s likely queried far more often than a booking’s dates ever change after creation. A table-level CHECK constraint (like CK_Booking_Dates) can reference multiple columns in the same row — just never another table or another row, which was exactly the boundary the previous lesson established.

    A Deterministic Requirement, Revisited

    -- FAILS: a computed column referencing GETDATE() cannot be PERSISTED or indexed,
    -- for the exact same non-deterministic reason a scalar function couldn't be (Chapter 2)
    ALTER TABLE dbo.Booking ADD days_until_checkin AS DATEDIFF(DAY, GETDATE(), check_in) PERSISTED;
    -- Msg 4936: Computed column 'days_until_checkin' in table 'Booking' cannot be persisted
    -- because the column is non-deterministic.
    Common mistake: Trying to PERSIST a computed column that depends on the current date/time or a random value, then being confused by the deterministic-function error. This is the same rule from Chapter 2’s scalar functions, applied to computed columns instead — a persisted value must be reproducible from its inputs alone, with nothing external sneaking in.
    Practice tip: Add a second computed column to Booking — is_long_stay AS CASE WHEN DATEDIFF(DAY, check_in, check_out) > 7 THEN 1 ELSE 0 END — and confirm you can filter on it directly in a WHERE clause, exactly like a normal column.

    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 for Developers & DBAs, coming soon on this site.