Ограничения целостности
Заставляем базу самостоятельно отвергать неверные данные с помощью ограничений.
Ограничение (constraint) — это правило на уровне таблицы, которое PostgreSQL проверяет при каждой вставке и обновлении, отклоняя данные, его нарушающие.
Зачем нужны ограничения
Можно проверять данные в коде приложения — но приложений может быть несколько, и каждое способно ошибиться. Ограничения переносят проверку в саму базу: что бы ни случилось, в таблицу не попадёт строка без обязательного поля, с отрицательной ценой или с дублирующимся email. Это последний и самый надёжный рубеж защиты.
Пять основных ограничений
| Ограничение | Что гарантирует |
PRIMARY KEY | уникальный и непустой идентификатор строки |
UNIQUE | значение не повторяется в столбце |
NOT NULL | значение обязательно (не может быть пустым) |
CHECK | значение удовлетворяет условию |
DEFAULT | значение по умолчанию, если не задано |
Пример с проверкой в песочнице
Соберём таблицу сотрудников с несколькими ограничениями и проверим, что корректные данные проходят. Пример переносимый.
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
salary INTEGER CHECK (salary > 0)
);
INSERT INTO employees (id, email, salary) VALUES
(1, '[email protected]', 90000),
(2, '[email protected]', 75000);
SELECT email, salary FROM employees ORDER BY salary DESC;
Вывод:
[email protected]|90000 [email protected]|75000
Здесь email обязателен (NOT NULL) и уникален (UNIQUE), а зарплата обязана быть положительной (CHECK). Попытка вставить второй такой же email или зарплату -100 завершилась бы ошибкой — база не пропустит.
CHECK — проверки на уровне таблицы
CHECK — самое гибкое ограничение: внутри можно записать почти любое логическое условие, в том числе с несколькими столбцами.
CREATE TABLE bookings (
id SERIAL PRIMARY KEY,
starts_at DATE NOT NULL,
ends_at DATE NOT NULL,
guests INTEGER NOT NULL,
-- условие с двумя столбцами:
CHECK (ends_at > starts_at),
CHECK (guests BETWEEN 1 AND 10)
);
Первое CHECK гарантирует, что дата выезда позже даты заезда, второе — что гостей от 1 до 10. Такие правила невозможно «забыть» применить — они часть таблицы.
Именованные ограничения
Ограничению можно дать имя через CONSTRAINT. Тогда в сообщении об ошибке будет понятное название, и ограничение легко удалить позже.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
sku TEXT,
price NUMERIC(10, 2),
CONSTRAINT uq_sku UNIQUE (sku),
CONSTRAINT positive_price CHECK (price >= 0)
);
Итог
- Ограничения переносят проверку данных в базу — это самый надёжный рубеж целостности.
PRIMARY KEY= уникальный + непустой;UNIQUEиNOT NULLпо отдельности тоже доступны.CHECKзадаёт произвольное условие, в том числе по нескольким столбцам; ограничениям можно давать имена черезCONSTRAINT.