До PostgreSQL 15 уникальные ограничения считали
NULL разными значениями. Это означало, что таблица спокойно принимала сколько угодно строк с NULL, даже если на колонке стоял UNIQUE.CREATE TABLE users (
email text UNIQUE
);
INSERT INTO users VALUES (NULL);
INSERT INTO users VALUES (NULL);
Обе вставки выполнятся успешно.
Если
NULL тоже должен быть уникальным, приходилось придумывать обходные пути. Кто-то делал частичные индексы, кто-то использовал COALESCE(), кто-то заводил отдельные флаги.CREATE TABLE users (
email text,
CONSTRAINT users_email_key
UNIQUE NULLS NOT DISTINCT (email)
);
INSERT INTO users VALUES (NULL);
INSERT INTO users VALUES (NULL);
Вторая вставка уже завершится ошибкой. Для ограничения
NULL считается таким же значением, как и любой другой ключ.CREATE TABLE users (
tenant_id int,
email text,
CONSTRAINT uq_user
UNIQUE NULLS NOT DISTINCT (tenant_id, email)
);
Полезно, когда
NULL — это полноценное значение предметной области, а не просто "неизвестно". UNIQUE.


