The SQL CHECK constraint lets you embed custom validation logic directly in a table definition. For every INSERT or UPDATE, the database evaluates the supplied boolean expression; if the expression does not return TRUE (or UNKNOWN when NULLs are allowed with the NOT VALID option in some dialects), the statement fails with an error. CHECK can be declared at the column level (applies only to that column) or at the table level (can reference multiple columns). Multiple CHECK constraints may coexist on a single table. Because the logic lives in the database, it protects data integrity regardless of the application writing to it.Important caveats:- Expressions cannot contain subqueries in some dialects (e.g., MySQL).- Functions used in the expression must be deterministic for optimal performance.- NULL handling: if any operand is NULL, most dialects treat the overall result as UNKNOWN, which passes the check unless the column is declared NOT NULL.- Disabling or dropping a CHECK requires ALTER TABLE. Some engines accept NOT VALID to add a constraint without scanning existing rows, followed by VALIDATE to enforce retrospectively.
constraint_name
(optional) - identifier - User-defined name for the constraintboolean_expression
(Boolean) - Condition that must evaluate to TRUE for every rowNOT NULL, UNIQUE, FOREIGN KEY, PRIMARY KEY, DEFAULT, ENUM
SQL-92
If any part of the expression is NULL, the result becomes UNKNOWN. Most engines treat UNKNOWN the same as TRUE for CHECK evaluation, so the row is accepted unless a NOT NULL constraint also fails.
Yes. Add it with NOT VALID (PostgreSQL) or WITH NOCHECK (SQL Server) to skip existing rows, then fix the data and run VALIDATE to enforce.
No. A CHECK is simpler, declarative, and runs automatically without procedural code. Triggers are more flexible but require writing and maintaining procedural logic.
The overhead is usually negligible for simple expressions. Complex expressions or the use of functions can increase CPU cost, but the trade-off is stronger data integrity.