Короткий ответ
PRIMARY KEY — это единственное на таблицу ограничение, идентифицирующее строку, автоматически NOT NULL; UNIQUE гарантирует отсутствие дублей в колонке(ах), но допускает NULL (в PostgreSQL несколько NULL допустимы), и таких ограничений может быть сколько угодно.
Как это работает подробнее
Оба ограничения реализуются через уникальный индекс. Разница в семантике: PK один на таблицу и используется как основной идентификатор для внешних ключей, UNIQUE может быть добавлен на любые колонки для бизнес-правил (например, email должен быть уникален).
Пример кода
example.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
phone TEXT UNIQUE
);
-- INSERT с одинаковым email -> ошибка unique violation
-- INSERT двух строк с phone = NULL -> успешно, так как NULL != NULLЧто использовать на практике
- Практика. Типичный паттерн — SERIAL/UUID как PK для внутренней идентификации плюс UNIQUE на email или на связке колонок (например, (user_id, role_id) для предотвращения дублирования связи).
Подводные камни
- Ошибка. Думают, что UNIQUE запрещает NULL — в PostgreSQL несколько строк с NULL в UNIQUE-колонке допустимы, так как NULL не равен NULL; если нужно запретить больше одной «пустой» записи, нужен отдельный partial unique index.