CHECK Constraint
A CHECK constraint attaches a custom boolean condition to a table or column. Every row, whether inserted or later updated, must satisfy that condition — if the expression evaluates to false, the database rejects the operation. Where PRIMARY KEY, FOREIGN KEY, UNIQUE, and NOT NULL each enforce one specific, built-in kind of rule, CHECK lets you encode any business rule you can express as a boolean expression.
Worked example
CREATE TABLE products ( product_id INT PRIMARY KEY, name VARCHAR(100) NOT NULL, price DECIMAL(10, 2) NOT NULL CHECK (price > 0), discount DECIMAL(4, 2) DEFAULT 0 CHECK (discount BETWEEN 0 AND 1) );
-- Fails: price must be greater than 0 INSERT INTO products (product_id, name, price) VALUES (1, 'Widget', -5.00);
ERROR: new row for relation "products" violates check constraint "products_price_check" DETAIL: Failing row contains (1, Widget, -5.00, 0.00).
Without this constraint, nothing stops a bug in an admin tool, a bad data import, or a careless manual UPDATE from setting a product's price to a negative number — a mistake that could silently corrupt every report and calculation built on top of the products table.
CHECK across multiple columns
A CHECK expression can reference more than one column, letting it enforce relationships between values in the same row:
CREATE TABLE bookings ( booking_id INT PRIMARY KEY, start_date DATE NOT NULL, end_date DATE NOT NULL, CHECK (end_date > start_date) );
This guarantees that no booking can ever be stored with an end date on or before its start date, regardless of which application or script created the row.
Adding a named CHECK constraint
ALTER TABLE bookings ADD CONSTRAINT chk_booking_dates CHECK (end_date > start_date);
Naming a constraint explicitly (with CONSTRAINT chk_booking_dates) makes the resulting error messages clearer and makes the constraint easier to drop or modify later, compared to relying on an auto-generated name.