PostgreSQL Tutorial: CHECK Constraint

August 1, 2023

Summary: in this tutorial, you will learn about the PostgreSQL CHECK constraints and how to use them to constrain values in columns of a table based on a boolean expression.

A CHECK constraint is a kind of constraint that allows you to specify if values in a column must meet a specific requirement.

The CHECK constraint uses a Boolean expression to evaluate the values before they are inserted or updated to the column.

If the values pass the check, PostgreSQL will insert or update these values to the column. Otherwise, PostgreSQL will reject the changes and issue a constraint violation error.

Define PostgreSQL CHECK constraint for new tables

Typically, you use the CHECK constraint at the time of creating the table using the CREATE TABLE statement.

The following statement defines an employees table.

DROP TABLE IF EXISTS employees;
CREATE TABLE employees (
	id SERIAL PRIMARY KEY,
	first_name VARCHAR (50),
	last_name VARCHAR (50),
	birth_date DATE CHECK (birth_date > '1900-01-01'),
	joined_date DATE CHECK (joined_date > birth_date),
	salary numeric CHECK(salary > 0)
);

The employees table has three CHECK constraints:

  • First, the birth date ( birth_date) of the employee must be greater than 01/01/1900. If you try to insert a birth date before 01/01/1900, you will receive an error message.
  • Second, the joined date ( joined_date) must be greater than the birth date ( birth_date). This check will prevent from updating invalid dates in terms of their semantic meanings.
  • Third, the salary must be greater than zero, which is obvious.

Let’s try to insert a new row into the employees table:

INSERT INTO employees (first_name, last_name, birth_date, joined_date, salary)
VALUES ('John', 'Doe', '1972-01-01', '2015-07-01', - 100000);

The statement attempted to insert a negative salary into the salary column. However, PostgreSQL returned the following error message:

ERROR:  new row for relation "employees" violates check constraint "employees_salary_check"
DETAIL:  Failing row contains (1, John, Doe, 1972-01-01, 2015-07-01, -100000).

The insert failed because of the CHECK constraint on the salary column that accepts only positive values.

By default, PostgreSQL gives the CHECK constraint a name using the following pattern:

{table}_{column}_check

For example, the constraint on the salary column has the following constraint name:

employees_salary_check

However, if you want to assign aCHECK constraint a specific name, you can specify it after the CONSTRAINT expression as follows:

column_name data_type CONSTRAINT constraint_name CHECK(...)

See the following example:

...
salary numeric CONSTRAINT positive_salary CHECK(salary > 0)
...

Define PostgreSQL CHECK constraints for existing tables

To add CHECK constraints to existing tables, you use the ALTER TABLE statement. Suppose, you have an existing table in the database named prices_list

CREATE TABLE prices_list (
	id serial PRIMARY KEY,
	product_id INT NOT NULL,
	price NUMERIC NOT NULL,
	discount NUMERIC NOT NULL,
	valid_from DATE NOT NULL,
	valid_to DATE NOT NULL
);

Now, you can use ALTER TABLE statement to add the CHECK constraints to the prices_list table. The price and discount must be greater than zero and the discount is less than the price. Notice that we use a Boolean expression that contains the AND operators.

ALTER TABLE prices_list 
ADD CONSTRAINT price_discount_check 
CHECK (
	price > 0
	AND discount >= 0
	AND price > discount
);

The valid to date ( valid_to) must be greater than or equal to valid from date ( valid_from).

ALTER TABLE prices_list 
ADD CONSTRAINT valid_range_check 
CHECK (valid_to >= valid_from);

The CHECK constraints are very useful to place additional logic to restrict values that the columns can accept at the database layer. By using the CHECK constraint, you can make sure that data is updated to the database correctly.

In this tutorial, you have learned how to use PostgreSQL CHECK constraint to check the values of columns based on a Boolean expression.

comments powered by Disqus