Технически, NULL = NULL является False, по этой логике никакой NULL не равен ни одному NULL, и все NULL различны. Разве это не означает, что все NULL являются уникальными, а уникальный индекс должен разрешать любое количество NULL?
Технически, NULL = NULL является False, по этой логике никакой NULL не равен ни одному NULL, и все NULL различны. Разве это не означает, что все NULL являются уникальными, а уникальный индекс должен разрешать любое количество NULL?
Ответы:
Почему это работает так? Потому что когда-то, когда кто-то принимал решение о дизайне, не зная и не заботясь о том, что говорит стандарт (в конце концов, у нас есть все виды странного поведения с NULL
s, и мы можем по своему усмотрению приводить к другому поведению). Это решение продиктовано , что в этом случае NULL = NULL
.
Это было не очень разумное решение. То, что они должны были сделать, - это установить поведение по умолчанию в соответствии со стандартом ANSI, и, если они действительно хотели это своеобразное поведение, разрешите его с помощью параметра DDL, например WITH CONSIDER_NULLS_EQUAL
или WITH ALLOW_ONLY_ONE_NULL
.
Конечно, задним числом 20/20.
И у нас есть обходной путь, теперь, во всяком случае, даже если он не самый чистый или самый интуитивный.
Вы можете получить правильное поведение ANSI в SQL Server 2008 и выше, создав уникальный отфильтрованный индекс.
CREATE UNIQUE INDEX foo ON dbo.bar(key) WHERE key IS NOT NULL;
Это допускает более одного NULL
значения, потому что эти строки полностью исключены из проверки на дубликаты. В качестве дополнительного бонуса это может привести к тому, что индекс станет меньшим, чем индекс, который состоит из всей таблицы, если будет NULL
разрешено несколько s (особенно, когда это не единственный столбец в индексе, у него есть INCLUDE
столбцы и т. Д.). Однако вы можете знать о некоторых других ограничениях отфильтрованных индексов:
Правильный. Реализация уникального ограничения или индекса на сервере SQL позволяет один и только один NULL. Также исправьте, что это технически не соответствует определению NULL, но это одна из тех вещей, которые они сделали, чтобы сделать его более полезным, даже если это не «технически» правильно. Обратите внимание, что PRIMARY KEY (также уникальный индекс) не допускает NULL (конечно).
Во-первых, перестаньте использовать фразу «Нулевое значение», это просто приведет вас в заблуждение. Вместо этого используйте фразу «нулевой маркер» - маркер в столбце, указывающий, что фактическое значение в этом столбце либо отсутствует, либо неприменимо (но обратите внимание, что маркер не говорит, какой из этих параметров действительно имеет место »).
Теперь представьте себе следующее (где база данных не обладает полным знанием моделируемой ситуации).
Situation Database
ID Code ID Code
-- ----- -- -----
1 A 1 A
2 B 2 (null)
3 C 3 C
4 B 4 (null)
Правило целостности, которое мы моделируем: «Код должен быть уникальным». В реальной ситуации это нарушается, поэтому база данных не должна допускать, чтобы оба элемента 2 и 4 были в таблице одновременно.
Самым безопасным и наименее гибким подходом было бы запретить нулевые маркеры в поле кода, поэтому нет возможности противоречивых данных. Наиболее гибкий подход - разрешить использование нескольких нулевых маркеров и беспокоиться об уникальности при вводе значений.
Программисты Sybase придерживались несколько безопасного, не очень гибкого подхода, предусматривающего использование только одного нулевого маркера в таблице - на что с тех пор комментаторы жалуются. Microsoft продолжила такое поведение, полагаю, для обратной совместимости.
Я уверен, что где-то читал, что Кодд рассматривал возможность реализации двух нулевых маркеров - один для неизвестного, другой для неприменимого - но отклонил его, но я не могу найти ссылку. Я правильно помню?
PS Моя любимая цитата о нуле: Луи Дэвидсон, «Профессиональный дизайн базы данных SQL Server 2000», Wrox Press, 2001, стр. 52. «Сводится к одному предложению: NULL - зло».
null
не достигает этой цели. Потому что пропущенное значение может оказаться таким же, как значение в одной из других строк.
CHECK (Value IN ('A','B','C','D'))
? Тогда и реализация SQL-Server, и стандарт SQL позволяют таблице иметь 5 строк (по одной строке для каждого значения плюс 1 с NULL.) Тогда, возможно, хотя база данных соответствует ее ограничениям, она не соответствует намерению разработчика таблица должна иметь максимум 4 строки. Нет значения, на которое можно изменить значение NULL, которое не будет нарушать ограничение, если только одна или несколько строк не будут удалены.
CREATE TABLE #T(A INT NULL UNIQUE);INSERT INTO #T VALUES (1),(NULL);UPDATE #T SET A = 1 WHERE A IS NULL;
выдаст ошибку. Согласно вашей теории мотивации дизайна, NULL
в первом случае следовало бы предотвратить вставку - потому что неполное знание означает, что нет никакой гарантии, что значение будет другим.
Это не может быть технически точным, но философски помогает мне спать по ночам ...
Как и некоторые другие говорили или ссылались, если вы думаете о NULL как о неизвестном, то вы не можете определить, действительно ли одно значение NULL равно другому значению NULL. Думая об этом, выражение NULL == NULL должно быть равно NULL, что означает неизвестность.
Ограничение Unique потребовало бы определенного значения для сравнения значений столбца. Другими словами, при сравнении значения одного столбца с любым другим значением столбца с использованием оператора равенства он должен иметь значение false, чтобы быть действительным. Неизвестное на самом деле не является ложным, хотя его часто считают ложным. Два значения NULL могут быть равными или нет ... это просто невозможно определить окончательно.
Это помогает думать об уникальном ограничении как об ограничении значений, которые могут быть определены как отличные друг от друга. Под этим я подразумеваю, что вы запускаете SELECT, который выглядит примерно так:
SELECT * from dbo.table1 WHERE ColumnWithUniqueContraint="some value"
Большинство людей ожидают одного результата, учитывая, что существует уникальное ограничение. Если вы разрешите несколько значений NULL в ColumnWithUniqueConstraint, то будет невозможно выбрать одну отдельную строку из таблицы, используя NULL в качестве сравниваемого значения.
Учитывая это, я считаю, что независимо от того, правильно ли он реализован в отношении определения NULL, в большинстве ситуаций это определенно намного практичнее, чем использование нескольких значений NULL.
Одной из основных целей UNIQUE
ограничения является предотвращение дублирования записей. Если необходимо иметь таблицу, в которой может быть несколько записей, где значение «неизвестно», но две записи не могут иметь одно и то же «известное» значение, тогда неизвестным значениям следует присвоить искусственные уникальные идентификаторы, прежде чем они будут добавлен в таблицу.
Есть несколько редких случаев, когда столбец имеет UNIQUE
ограничение и содержит одно нулевое значение; например, если таблица содержит отображение между значениями столбцов и локализованными текстовыми описаниями, строка для NULL
позволит определить описание, которое должно отображаться, когда этот столбец находится в какой-то другой таблице NULL
. ПоведениеNULL
позволяет для этого случая использования.
В противном случае я не вижу оснований для базы данных с UNIQUE
ограничением на какой-либо столбец, позволяющей существование множества идентичных записей, но я не вижу способа предотвратить это, допуская при этом несколько записей, значения ключей которых не различимы. Объявление, что NULL
оно не равно самому себе, не сделает NULL
значения отличимыми друг от друга.