Skip to content
C

Table Constraints


Table Constraints

Definition

A table constraint is written as its own separate clause inside CREATE TABLE (or added via a standalone ALTER TABLE ... ADD CONSTRAINT), rather than being attached inline to one column's definition. Syntactically it appears at the same level as a column definition, listed among the table's columns, but it names the column(s) it applies to explicitly inside parentheses rather than relying on inline placement.

Why Table Constraints Exist: The Multi-Column Requirement

The defining reason table-level syntax exists is that some rules inherently span more than one column, and there is no single column to visually "attach" them to:

sql
CREATE TABLE enrollments ( student_id INT, course_id INT, grade CHAR(2), enrolled_on DATE, completed_on DATE, PRIMARY KEY (student_id, course_id), -- composite key: 2 columns CHECK (completed_on IS NULL OR completed_on >= enrolled_on), -- 2 columns FOREIGN KEY (student_id) REFERENCES students(student_id) );

The composite PRIMARY KEY and the multi-column CHECK are only expressible this way — there is no column-level equivalent for either.

Full Syntax Forms

sql
CREATE TABLE t ( col1 INT, col2 INT, CONSTRAINT pk_t PRIMARY KEY (col1, col2), CONSTRAINT uq_t UNIQUE (col1), CONSTRAINT chk_t CHECK (col1 < col2), CONSTRAINT fk_t FOREIGN KEY (col2) REFERENCES other_table(id) );

Every constraint type — PRIMARY KEY, UNIQUE, CHECK, FOREIGN KEY — has a valid table-level form. NOT NULL is the sole exception: it has no table-level form at all, since "not null" is inherently a per-column property with no meaningful multi-column phrasing.

A table constraint doesn't strictly require multiple columns; it's legal (if slightly more verbose) to write a single-column rule at table level too:

sql
CREATE TABLE employees ( emp_id INT, salary NUMERIC(10,2), CONSTRAINT chk_salary_positive CHECK (salary > 0) -- table-level, but only touches 1 column );

This is functionally identical to writing CHECK (salary > 0) inline on the salary column — the choice here is purely stylistic (some teams standardize on always using table-level clauses grouped at the bottom of the CREATE TABLE for readability, even for single-column rules).

Adding Table Constraints After Creation

sql
ALTER TABLE enrollments ADD CONSTRAINT chk_dates CHECK (completed_on IS NULL OR completed_on >= enrolled_on);

ALTER TABLE ... ADD CONSTRAINT is inherently a "table constraint" operation — there is no way to retroactively splice a constraint into the middle of an existing column's inline definition; anything added later is structurally a table-level addition even if it only touches one column.

Edge Cases

  • Table constraints are always comma-separated siblings of column definitions inside the CREATE TABLE parentheses — order relative to columns doesn't matter for evaluation, only for readability.
  • A single CREATE TABLE can mix column-level and table-level constraints freely in the same statement.
  • Some style guides mandate table-level syntax for every constraint (even single-column ones) specifically to keep constraint management centralized and easy to scan/audit in one place near the bottom of the DDL.

Key Takeaways / Q&A

Q: Which constraint type has no table-level form at all? A: NOT NULL — it is exclusively a column-level, per-column property.

Q: Is it valid to write a single-column CHECK at table level? A: Yes, it's legal and purely a stylistic choice, functionally identical to the column-level version.

Q: Why is a composite PRIMARY KEY unavoidably a table constraint? A: Because it spans two or more columns, and there's no single column definition it could be attached to inline.

Mock Test

  • Table Constraints - Quick Test

    8 questions on Table Constraints.

    8 questions · 8 min · Medium
    Start Mock Test