Для сотрудников задана уникальность пары «отдел — рабочий email». Разрешает ли это повторить один email в р...

Для сотрудников задана уникальность пары «отдел — рабочий email». Разрешает ли это повторить один email в разных отделах?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Да. Ограничение уникальности для пары отдел — рабочий email запрещает только повторение одинаковой комбинации этих двух значений, но не одинакового email при разных отделах. Для глобальной уникальности email нужно добавить отдельное ограничение UNIQUE на один столбец email.

Если требуются оба правила — уникальность email внутри отдела и во всей организации — задают оба ограничения. Если email допускает NULL, его поведение при UNIQUE зависит от СУБД; для обязательного рабочего адреса обычно дополнительно задают NOT NULL.

Исторический контекст

В реляционной модели ключ описывает, какие значения однозначно идентифицируют строку в заданном отношении. На практике идентификатор может быть уникален не глобально, а только в определённом контексте: например, номер кабинета уникален внутри здания, но повторяется в разных зданиях.

Составные ограничения уникальности появились как способ выразить такую контекстную идентичность на уровне схемы. Это переносит правило из прикладного кода в базу данных и защищает его независимо от того, какой сервис изменяет данные.

Постановка проблемы

Предположим, организация разрешает одному и тому же сотруднику иметь рабочий email только один раз в каждом отделе, но одинаковые адреса в разных отделах допустимы. Уникальность пары отдел и email соответствует этому правилу.

Ошибка возникает, когда разработчик принимает составную уникальность за глобальную. Тогда база данных отклонит только вторую строку с теми же отделом и email, но примет строку с тем же email и другим отделом. Если бизнес-правило требует глобальной уникальности, это создаёт дубликаты идентификатора.

Обратная ошибка тоже опасна: глобальный UNIQUE на email запретит допустимое повторное использование адреса в разных изолированных подразделениях.

Подробное решение

Составное ограничение UNIQUE(отдел, email) проверяет уникальность кортежа значений. Нарушением будет только наличие двух строк, у которых одновременно совпадают отдел и email.

CREATE TABLE employee_contact ( employee_id INTEGER PRIMARY KEY, department_id INTEGER NOT NULL, work_email VARCHAR(320) NOT NULL, CONSTRAINT uq_department_email UNIQUE (department_id, work_email), CONSTRAINT uq_work_email UNIQUE (work_email) );

В примере первое ограничение защищает уникальность email внутри отдела, а второе — глобальную уникальность. Если нужно только первое правило, глобальное ограничение добавлять нельзя: оно изменит допустимое множество данных.

Важно отличать область уникальности от способа физической реализации. СУБД обычно создаёт индекс для UNIQUE, но смысл ограничения определяется всем набором его столбцов, а не тем, что индекс существует.

Нужно отдельно учитывать NULL. В большинстве распространённых СУБД несколько строк с NULL в уникальном столбце не считаются дубликатами, поскольку NULL означает неизвестное или отсутствующее значение; конкретное поведение и способы задать альтернативную семантику зависят от СУБД. Поэтому для обязательного адреса следует использовать NOT NULL, а для условной уникальности — явно проектировать нужное правило.

Ситуация из практики

В компании email сотрудников обычно уникален глобально, но временные подрядчики могут использовать один корпоративный адрес в разных проектах. Команда рассматривала два варианта: оставить только UNIQUE по паре проект и email либо сделать глобальный UNIQUE по email.

Первый вариант позволял нежелательные дубли среди штатных сотрудников. Второй вариант блокировал допустимые записи подрядчиков. Окончательное решение разделило сущности и правила: для штатного аккаунта задали глобальную уникальность идентификатора, а для проектного контакта — уникальность в пределах проекта; результатом стали независимые ограничения без смешения разных бизнес-смыслов.

Если обе категории всё же хранятся в одной таблице, можно использовать отдельные ограничения, но условие должно быть выражено так, чтобы разные типы записей не начинали ошибочно конкурировать за один и тот же ключ. На практике для сложной условной уникальности применяют частичный или функциональный индекс, если это поддерживает выбранная СУБД.

Что кандидаты часто упускают

  1. Можно ли оставить только UNIQUE по email, если уже есть UNIQUE по паре отдел — email?

Нет, составное ограничение не подразумевает уникальность каждого отдельного столбца. Оно разрешает строки с одинаковым email, если отделы различаются. Отдельный UNIQUE по email нужен для глобального правила.

  1. Что изменится, если отдел или email допускает NULL?

Смысл ограничения становится менее очевидным: сравнение с NULL не даёт обычного равенства, поэтому несколько строк с отсутствующим значением часто проходят UNIQUE. Если отсутствие отдела недопустимо, его объявляют NOT NULL; если отсутствие email допустимо, нужно заранее определить, должны ли такие строки считаться повторными, и выбрать поддерживаемый СУБД способ реализации.

  1. Может ли составное UNIQUE быть целью внешнего ключа?

Да, если внешний ключ ссылается на тот же набор столбцов и в том же порядке, а целевая комбинация действительно гарантированно уникальна. Это позволяет ссылаться, например, на пару отдел — email, но не позволяет ссылаться только на email, пока для email отдельно не задана уникальность.

Такое требование важно для ссылочной целостности: без уникальной цели СУБД не может однозначно определить, на какую родительскую строку указывает дочерняя запись.