Each check constraint has to be defined in the CREATE TABLE or ALTER TABLE statement using the syntax:
If the check constraint refers to a single column only, it is possible to specify the constraint as part of the column definition.
A NOT NULL constraint is functionally equivalent to the following check constraint with an IS NOT NULL predicate:
Some relational database management systems are able to optimize performance when the NOT NULL constraint syntax is used as opposed to the CHECK constraint syntax given above.1
Most database management systems restrict check constraints to a single row, with access to constants and deterministic functions, but not to data in other tables, or to data invisible to the current transaction because of transaction isolation.
Such constraints are not truly table check constraints but rather row check constraints. Because these constraints are generally only verified when a row is directly updated (for performance reasons,) and often implemented as implied INSERT or UPDATE triggers, integrity constraints could be violated by indirect action were it not for these limitations. Furthermore, otherwise-valid modifications to these records would then be prevented by the CHECK constraint. Some examples of dangerous constraints include:
User-defined triggers can be used to work around these restrictions. Although similar in implementation, it is semantically clear that triggers will only be fired when the table is directly modified, and that it is the designer's responsibility to handle indirect, important changes in other tables; constraints on the other hand are intended to be "true at all times" regardless of the user's actions or the designer's lack of foresight.
PostgreSQL 13 Documentation, Chapter 5. Data Definition, Section 5.4.2. Not-Null Constraints, Website: https://www.postgresql.org/docs/13/ddl-constraints.html, Accessed on Jan 9, 2021 https://www.postgresql.org/docs/13/ddl-constraints.html ↩