Dataslope logoDataslope

Check Constraints

Learn how CHECK constraints encode domain rules such as valid prices, statuses, and date ranges directly in the schema.

A product with a negative price is not a discounted product. It is bad data. An order with status banana is not creative; it is invalid.

A CHECK constraint lets the schema say those things out loud.

CHECK encodes a domain rule

A CHECK constraint is a boolean expression that must be true for every row. If the expression is false, PostgreSQL rejects the write.

The expression can refer to columns in the same row. That makes CHECK a natural fit for rules like:

  • price >= 0
  • quantity > 0
  • status IN ('draft', 'published', 'archived')
  • end_date > start_date

These are domain rules: they define which values make sense for the kind of thing the table stores.

Business rule to schema rule

The most important design move is translating a sentence about the business into a rule the database can enforce.

Once the rule lives in the schema, it applies to every writer. No import job, admin script, or forgotten form can sneak around it.

CHECK is a guardrail

A CHECK constraint is especially useful when a value has a small valid range, a minimum or maximum, or a relationship to another column in the same row.

Watch CHECK reject bad values

This table protects two rules: product prices cannot be negative, and status must be one of a small set of allowed values.

SQL
PostgreSQL 17

The error is the lesson: the schema refuses to contain rows that break its definition of a valid product.

CHECK with multiple columns

CHECK constraints can compare columns in the same row. For an event, end_date should come after start_date.

SQL
PostgreSQL 17

This is still one-row logic. CHECK is excellent for rules that can be decided by looking at the row being written.

Quick check

QuestionSelect one

Which business rule is a natural fit for a CHECK constraint?

Every order must reference an existing customer.

A product price must be greater than or equal to zero.

Every email must be different from every other email.

Every row must have a primary key.

CHECK vs. other constraints

CHECK is one member of the constraint family. It does not replace the others.

If the rule is "this value is required," use NOT NULL. If the rule is "this value cannot repeat," use UNIQUE. If the rule is "this reference must exist," use FOREIGN KEY. If the rule is "this expression must be true for the row," use CHECK.

A note about NULL and CHECK

At a beginner level, the safe pattern is simple: combine CHECK with NOT NULL when the value is required.

Why? SQL treats NULL as unknown. A CHECK constraint rejects false, but a NULL expression may be unknown rather than false. If the column must be present, say that directly with NOT NULL.

For example, prefer price NUMERIC NOT NULL CHECK (price >= 0) when every product must have a price.

Quick check

QuestionSelect one

Why are NOT NULL and CHECK (price >= 0) often used together for a required price?

CHECK automatically creates a price when it is missing.

NOT NULL requires the value to exist, and CHECK requires the existing value to be valid.

NOT NULL prevents duplicate prices.

CHECK makes the column a primary key.

Check your understanding

QuestionSelect one

What does a CHECK constraint do?

It checks whether a query returned at least one row.

It requires a boolean expression to be true for each row being inserted or updated.

It checks spelling in text columns.

It checks whether the database has a backup.

QuestionSelect one

Which SQL fragment best enforces that status is one of three allowed values?

status TEXT UNIQUE

status TEXT DEFAULT 'draft'

status TEXT CHECK (status IN ('draft', 'active', 'archived'))

status TEXT REFERENCES status

QuestionSelect one

A rule says end_date must be after start_date in the same row. Which constraint type fits best?

DEFAULT.

UNIQUE.

CHECK.

FOREIGN KEY.

On this page