Что случилось с столбцы с нулевым значением в составных первичных ключах?
ORACLE не разрешает значения NULL ни в одном из столбцов, составляющих первичный ключ. Похоже, что то же самое верно и для большинства других систем "корпоративного уровня".
в то же время, большинство систем также позволит уникальный противопоказания для столбцов с нулевым значением.
Почему уникальные ограничения могут иметь нули, но первичные ключи не могут? Есть фундаментальные причины для этого, или это скорее техническое ограничение?
6 ответов:
первичные ключи предназначены для уникальной идентификации строк. Это делается путем сравнения всех частей ключа к входной.
в определении NULL не может быть частью успешного сравнения. Даже сравнение с самим собой (
NULL = NULL
) не удастся. Это означает, что ключ, содержащий NULL, не будет работать.Additonally, NULL разрешено во внешнем ключе, чтобы отметить необязательную связь.(*) позволяя ему в ПК, а также сломать этот.
(*)предупреждение: наличие обнуляемых внешних ключей не является чистым дизайном реляционной базы данных.
если есть два объекта
A
иB
здесьA
может быть дополнительно связано сB
, чистое решение заключается в создании таблицы разрешения (скажемAB
). Эта таблица будет ссылатьсяA
СB
: Если есть и отношения, то он будет содержать запись, если там не затем он не будет.
первичный ключ определяет уникальный идентификатор для каждый строку в таблице: если таблица имеет первичный ключ, у вас есть гарантированный способ выбрать любую строку из него.
уникальное ограничение не обязательно идентифицирует каждую строку; оно просто указывает, что если строка имеет значения в своих столбцах,затем они должны быть уникальными. Этого недостаточно для однозначной идентификации каждый строка, что и должен делать первичный ключ.
принципиально ничего не говорю плохого с нулем в нескольких столбцов первичного ключа. Но наличие одного имеет последствия, которые дизайнер, вероятно, не намеревался, поэтому многие системы бросают ошибку, когда вы пытаетесь это сделать.
рассмотрим случай версий модуля / пакета, хранящихся в виде ряда полей:
CREATE TABLE module (name varchar(20) PRIMARY KEY, description text DEFAULT '' NOT NULL); CREATE TABLE version (module varchar(20) REFERENCES module, major integer NOT NULL, minor integer DEFAULT 0 NOT NULL, patch integer DEFAULT 0 NOT NULL, release integer DEFAULT 1 NOT NULL, ext varchar(20), notes text DEFAULT '' NOT NULL, PRIMARY KEY (module, major, minor, patch, release, ext));
первые 5 элементов первичного ключа регулярно определенными частями версии, но некоторые пакеты имеют настраиваемое расширение, которое обычно не целое число (например, " rc-foo "или" vanilla "или" beta " или что-то еще, для кого четыре полей недостаточно может выдумать). Если пакет не имеет расширения, то он является нулевым в приведенной выше модели, и никакого вреда не будет сделано, оставив вещи таким образом.
а то и a NULL? Он должен представлять собой отсутствие информации, неизвестной. Тем не менее, возможно, это имеет больше смысла:
CREATE TABLE version (module varchar(20) REFERENCES module, major integer NOT NULL, minor integer DEFAULT 0 NOT NULL, patch integer DEFAULT 0 NOT NULL, release integer DEFAULT 1 NOT NULL, ext varchar(20) DEFAULT '' NOT NULL, notes text DEFAULT '' NOT NULL, PRIMARY KEY (module, major, minor, patch, release, ext));
в этой версии "ext" часть кортежа не является NULL, но по умолчанию пустая строка-которая семантически (и практически) отличается от NULL. Значение NULL является неизвестным, в то время как пустая строка является преднамеренным определением "чего-то нет". Другими словами," пустой "и" нулевой " - это разные вещи. Это разница между "у меня нет ценности здесь" и "я не знаю, что такое ценность здесь."
при регистрации пакета, в котором отсутствует расширение версии вы знаю it отсутствует расширение, поэтому пустая строка на самом деле является правильным значением. Значение NULL будет правильным только в том случае, если вы не знаете, есть ли у него расширение или нет. С этой ситуацией легче иметь дело в системах, где строковые значения являются нормой, потому что нет никакого способа представить "пустое целое число", кроме вставки 0 или 1, которое будет свернуто в любых сравнениях, сделанных позже (что имеет свои собственные последствия).
кстати, оба способа действительны в Postgres (так как мы обсуждая" enterprise " RDMBSs), но результаты сравнения могут сильно отличаться, когда вы бросаете NULL в микс-потому что NULL == "не знаю", поэтому все результаты сравнения с участием NULL заканчиваются нулем, так как вы не можете знать что-то неизвестное. Таким образом, это может быть источником тонких ошибок при сортировке, сравнении и т. д. Postgres предполагает, что вы взрослый человек и можете принять это решение самостоятельно. Oracle и DB2 предполагают, что вы не поняли, что делаете что-то глупое, и выдаете ошибку. Этот это обычно правильная вещь, но не всегда - вы могли бы на самом деле не знать и иметь NULL в некоторых случаях и, следовательно, оставляя строку с неизвестным элементом, против которого значимые сравнения невозможны, является правильным поведением.
в любом случае вы должны стремиться исключить количество пустых полей, которые вы разрешаете по всей схеме, и вдвойне, когда речь заходит о полях, которые являются частью первичного ключа. В подавляющем большинстве случаев наличие Пустые столбцы-это признак ненормализованного (в отличие от намеренно ненормализованного) дизайна схемы и должны быть очень тщательно продуманы до принятия.
NULL == NULL - > false (по крайней мере, в СУБД)
таким образом, вы не сможете получить какие-либо отношения, используя нулевое значение даже с дополнительными столбцами с реальными значениями.
ответ Тони Эндрюса является достойным. Но реальный ответ заключается в том, что это было соглашение, используемое сообществом реляционных баз данных, и не является необходимостью. Может быть, это хорошая конвенция, а может и нет.
сравнение чего-либо с нулем приводит к неизвестному (3-е значение истины). Так что, как было предложено с нулями, вся традиционная мудрость относительно равенства уходит в окно. Ну вот как это выглядит на первый взгляд.
но я не думаю, что это обязательно так и даже базы данных SQL не думают, что NULL уничтожает все возможности для сравнения.
запустите в своей базе данных запрос ВЫБЕРИТЕ * ИЗ ЗНАЧЕНИЙ (NULL) СОЮЗ ВЫБЕРИТЕ * ИЗ ЗНАЧЕНИЙ (NULL)
вы видите только один кортеж с одним атрибутом, который имеет значение NULL. Таким образом, объединение признало здесь два нулевых значения равными.
при сравнении составного ключа, имеющего 3 компонента, с кортежем с 3 атрибутами (1, 3, NULL) = (1, 3, NULL) 1 = 1 и 3 = 3 и NULL = НОЛЬ Результат этого неизвестен.
но мы могли бы определить новый вид оператора сравнения, например. ==. Х == Г Х = Y ИЛИ (X РАВЕН НУЛЮ, А Y ИМЕЕТ ЗНАЧЕНИЕ NULL)
наличие такого оператора равенства сделало бы составные ключи с нулевыми компонентами или несоставной ключ с нулевым значением беспроблемным.
Я все еще считаю, что это фундаментальный / функциональный недостаток, вызванный технической стороной. Если у вас есть необязательное поле, с помощью которого вы можете идентифицировать клиента, теперь вам нужно взломать фиктивное значение в него, просто потому, что NULL != NULL, не особенно элегантный, но это "отраслевой стандарт"