Столбец объявлен уникальным: почему это ещё не делает его первичным ключом?
Уникальность и первичный ключ решают разные задачи. Ограничение UNIQUE запрещает дублирование допустимых значений, но обычно допускает NULL и не требует, чтобы столбец был единственным главным идентификатором строк. Первичный ключ одновременно обеспечивает уникальность, запрет NULL и задаёт основной способ идентификации строк в отношении.
В реляционной модели ключ нужен для однозначной идентификации кортежа и поддержки ссылочной целостности. На практике у сущности может быть несколько уникальных способов идентификации: например, внутренний идентификатор и адрес электронной почты.
SQL разделяет эти роли: PRIMARY KEY обозначает основной ключ отношения, а UNIQUE позволяет объявлять альтернативные кандидатные ключи или бизнес-ограничения. Такое разделение поддерживает одновременно техническую идентификацию строки и контроль уникальности предметных данных.
Если заменить первичный ключ обычным UNIQUE-ограничением, можно ошибочно считать столбец полноценным идентификатором. Это опасно, когда в нём разрешён NULL: отсутствие значения не идентифицирует строку и может встречаться у нескольких записей.
Кроме того, у таблицы может быть только один первичный ключ, но несколько ограничений UNIQUE. Поэтому UNIQUE не сообщает, какой именно набор атрибутов является главным ключом сущности.
Первичный ключ обладает тремя важными свойствами: его значения уникальны, ни один компонент ключа не равен NULL, а сам ключ является главным идентификатором строк таблицы. Для составного первичного ключа правило отсутствия NULL применяется к каждому его компоненту.
Ограничение UNIQUE требует отсутствия дублирующихся значений, но поведение NULL основано на том, что NULL не является обычным сравнимым значением. В стандартной SQL-логике несколько строк с NULL в уникальном столбце обычно не считаются дубликатами; конкретные СУБД могут предоставлять дополнительные настройки вроде трактовки NULL как одинаковых значений.
Здесь customer_id обязан быть уникальным и непустым. email не может содержать два одинаковых известных значения, но две строки с NULL обычно допустимы.
UNIQUE может быть составным и тогда контролирует уникальность комбинации атрибутов, а не каждого атрибута отдельно. Такое ограничение подходит для альтернативного ключа, например уникальной пары «организация — внешний идентификатор».
Ограничения UNIQUE часто могут быть целями внешних ключей, если СУБД и конкретное ограничение удовлетворяют правилам ссылочной целостности. Однако при проектировании важно явно решить, допускается ли NULL и означает ли он «значение неизвестно», «значение не применимо» или ошибку данных.
В системе клиентов адрес электронной почты должен быть уникальным, но он необязателен: часть клиентов регистрируется без него. Внутренний идентификатор должен стабильно использоваться во внешних ключах и не зависеть от изменения email.
Вариант с одним UNIQUE на email прост и допускает отсутствие адреса, но не подходит как основной идентификатор: NULL не идентифицирует клиента, а изменение email затрагивает бизнес-данные. Вариант с email как PRIMARY KEY запрещает клиентов без email и связывает техническую модель с изменяемым атрибутом.
Рациональное решение — отдельный неизменяемый customer_id как PRIMARY KEY и дополнительное UNIQUE-ограничение на email. В результате внешние ссылки используют стабильный ключ, а уникальность известных адресов сохраняется без запрета регистрации клиентов без email.
Нет, обычное UNIQUE-ограничение для nullable-столбца обычно не предназначено для такого правила. Несколько NULL, как правило, допустимы, потому что NULL означает отсутствие известного значения, а не конкретное значение, равное другому NULL.
Если требуется не более одного отсутствующего значения, это нужно выражать отдельным механизмом, зависящим от СУБД: специальным индексом, частичным или функциональным индексом, либо проверкой на уровне модели данных. Нельзя выводить такое правило только из наличия UNIQUE.
У отношения может существовать несколько минимальных наборов атрибутов, однозначно идентифицирующих строки. Все такие наборы являются кандидатными ключами, но один из них выбирают в качестве первичного, а остальные объявляют альтернативными ключами через UNIQUE.
Например, внутренний номер клиента и подтверждённый email могут оба быть уникальными, но номер обычно выбирают первичным из-за стабильности и меньшей зависимости от бизнес-правил. Выбор PRIMARY KEY — это не отрицание уникальности остальных ключей, а выделение главного идентификатора.
Нет, нужно учитывать правила конкретной СУБД и форму ограничения. Для ссылки обычно требуется уникальный кандидатный ключ: один столбец или комбинация столбцов с подходящим UNIQUE-ограничением либо уникальным индексом, если СУБД разрешает использовать его для этой цели.
Составной уникальный ключ нельзя заменить уникальностью отдельных его компонентов: уникальность пары «организация — номер» не означает уникальность одного номера во всей таблице. Поэтому внешний ключ должен ссылаться на полный совместимый набор столбцов, иначе ссылочная целостность не будет однозначной.