Почему NULL = NULL оценивается как ложное в SQL-сервере - PullRequest
127 голосов
/ 04 декабря 2009

На сервере SQL, если в предложении where указано nullParam=NULL, оно всегда оценивается как ложное. Это нелогично и вызвало у меня много ошибок. Я понимаю, что ключевые слова IS NULL и IS NOT NULL являются правильным способом сделать это. Но почему SQL-сервер ведет себя так?

Ответы [ 16 ]

190 голосов
/ 04 декабря 2009

В этом случае думайте о нуле как о «неизвестном» (или «не существует»). В любом из этих случаев вы не можете сказать, что они равны, потому что вы не знаете ценность любого из них. Итак, null = null оценивается как не true (false или null, в зависимости от вашей системы), потому что вы не знаете значений, чтобы сказать, что они равны. Это поведение определено в стандарте ANSI SQL-92.

EDIT: Это зависит от ваших настроек ansi_nulls . если вы отключили ANSI_NULLS, это БУДЕТ иметь значение true. Запустите следующий код для примера ...

set ansi_nulls off

if null = null
    print 'true'
else
    print 'false'


set ansi_nulls ON

if null = null
    print 'true'
else
    print 'false'
114 голосов
/ 02 февраля 2014

Сколько лет Фрэнку? Я не знаю (ноль).

Сколько лет Ширли? Я не знаю (ноль).

Фрэнк и Ширли одного возраста?

Правильный ответ должен быть «я не знаю» (ноль), а не «нет», поскольку Фрэнк и Ширли могут быть одного возраста, мы просто не знаем

24 голосов
/ 04 декабря 2009

Здесь я надеюсь уточнить мою позицию.

То, что NULL = NULL оценивается как FALSE, неверно. Хакер и Мистер правильно ответили NULL. Вот почему. Дуэйн Кристенсен написал мне в комментарии к Скотту Айви :

Так как это декабрь, давайте использовать сезонный пример. У меня есть два подарка под деревом. Теперь скажи мне, если я есть два одинаковых или нет.

Они могут быть разными или равными вы не знаете до тех пор, пока не откроете оба подарка. Кто знает? Вы пригласили двух людей, которые не знают друг друга и оба сделали вам один и тот же подарок - редкий, но не невозможный § .

Итак, вопрос: эти два НЕИЗВЕСТНЫХ представляют одно и то же (равны =)? Правильный ответ: НЕИЗВЕСТНО (т.е. NULL).

Этот пример был предназначен для демонстрации того, что «.. (false или null, в зависимости от вашей системы) ..» является правильным ответом - это не так, только NULL правильно в 3VL (или вы можете принять систему, которая дает неправильные ответы?)

Правильный ответ на этот вопрос должен подчеркнуть следующие два момента:

  • трехзначная логика (3VL) нелогична (см. Бесчисленное множество других вопросов по этому вопросу в Stackoverflow и на других форумах, чтобы убедиться в этом);
  • СУБД на основе SQL часто не уважают даже 3VL, иногда они дают неправильные ответы (как утверждают первоначальные авторы, SQL Server в этом случае).

Поэтому я повторяю: SQL не имеет смысла заставлять интерпретировать рефлексивное свойство равенства, которое утверждает, что:

for any x, x = x §§ (на простом английском языке: независимо от вселенной дискурса, «вещь» всегда равна себе ).

.. в 3VL (TRUE, FALSE, NULL). Ожидание людей будет соответствовать 2VL (TRUE, FALSE, что даже в SQL допустимо для всех других значений), то есть x = x всегда оценивается как TRUE для любого возможного значения из х - без исключений.

Обратите также внимание, что NULL являются действительными " ненулевыми значениями " (так, как их притворяются их апологеты), которые можно назначать в качестве значений атрибутов (??) как часть переменных отношения. Таким образом, они являются приемлемыми значениями любого типа (домена), а не только типа логических выражений.

И это была моя точка зрения : NULL, как значение, является "странным зверем". Без эвфемизма я предпочитаю говорить: вздор .

Я думаю, что эта формулировка гораздо более ясна и менее спорна - извините за мое плохое знание английского языка.

Это только одна проблем с NULL. Лучше избегать их полностью, когда это возможно.

§ мы обеспокоены значениями здесь, поэтому тот факт, что два подарка всегда два разных физических объекта, не является действительным возражением; если вы не уверены, извините, это не то место, чтобы объяснить разницу между значением и семантикой «объекта» (Реляционная алгебра имеет семантику значения с самого начала - см. информационный принцип Кодда; я думаю, что некоторые разработчики СУБД SQL не даже не заботится об общей семантике).

§§ Насколько мне известно, это аксиома, принятая (в той или иной форме, но всегда интерпретируемая в 2VL) с древности и которая точно , потому что она настолько интуитивна. 3VLs (в действительности это семейство логик) - это гораздо более свежая разработка (но я не уверен, когда она была впервые разработана).

Примечание: , если кто-то введет Низ , Единица и Опция В качестве попыток обоснования значений NULL SQL я буду убедившись только после довольно подробного изучения, он покажет, как реализации SQL с NULL имеют систему типов звука, и, наконец, выяснит, что на самом деле представляют собой NULL (эти «значения-не-значения-значения»).


В дальнейшем я процитирую некоторых авторов. Любая ошибка или упущение вероятнолы мои а не оригинальных авторов.

Джо Селко о пустых значениях SQL

Я вижу, что Джо Селко часто цитируется на этом форуме. Видимо, он очень уважаемый автор здесь. Итак, я сказал себе: «Что он пишет о SQL NULL? Как он объясняет NULL многочисленные проблемы?». У одного из моих друзей есть электронная версия SQL Джо Селко для умных людей: продвинутый SQL-программирование, 3-е издание . Посмотрим.

Сначала оглавление. Больше всего меня поражает количество упоминаний NULL в самых разных контекстах:

3,4 Арифметика и NULL 109
3.5. Преобразование значений в NULL 110 и обратно.
3.5.1 Функция NULLIF () 110
6 NULL: отсутствуют данные в SQL 185
6.4 Сравнение значений NULL 190
6.5 NULL и логика 190
6.5.1 NULL в предикатах подзапроса 191
6.5.2 Стандартные решения SQL 193
6.6 Математика и нули 193
6.7 Функции и NULL 193
6,8 NULL и языки хоста 194
6.9. Советы по проектированию для NULL 195
6.9.1 Избегание пустых значений из программ хоста 197
6.10. Замечание о нескольких значениях NULL 198
10.1 НЕДЕЙСТВИТЕЛЬНО Предикат 241
10.1.1 Источники NULL 242
...

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

Я рассмотрю некоторые из этих случаев с выдержками из этой книги, пытаясь ограничить себя существенным по причинам авторского права. Я думаю, что эти цитаты подпадают под доктрину «добросовестного использования», и они могут даже стимулировать покупку книги - поэтому я надеюсь, что никто не будет жаловаться (в противном случае мне придется удалить большую часть, если не все). Кроме того, я буду воздерживаться от сообщения фрагментов кода по той же причине. Извини за это. Купите книгу, чтобы прочитать о данных рассуждениях.

Номера страниц между круглыми скобками в дальнейшем.

Ограничение NOT NULL (11)

Наиболее важным ограничением столбца является NOT NULL, что запрещает использование значений NULL в столбце. Используйте это ограничение регулярно и удалите это только когда у тебя есть веская причина. Это поможет вам избежать осложнения значения NULL при выполнении запросов к данным.

Это не значение ; это маркер, который содержит место, куда может пойти значение.

Опять эта ерунда "ценность, но не совсем ценность". Остальное мне кажется вполне разумным.

(12)

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

По поводу SQL, NULL и бесконечности:

(104) ГЛАВА 3: ЧИСЛЕННЫЕ ДАННЫЕ В SQL

SQL не принял модель IEEE для математики по нескольким причинам.

...

Если бы правила IEEE по математике были разрешены в SQL, то нам нужны правила преобразования типов для бесконечного и способ представляют бесконечное точное числовое значение после преобразования. люди У меня достаточно проблем с NULL, так что давайте не будем идти туда.

Реализации SQL не определились с тем, что на самом деле означает NULL в определенных контекстах:

3.6.2 Экспоненциальные функции (116)

Проблема в том, что логарифмы не определены, когда (x <= 0). <strong>Немного SQL реализации возвращают сообщение об ошибке, некоторые возвращают NULL и DB2 / 400; версия 3, выпуск 1 возвращен * NEGINF (сокращение от «минус бесконечность») как результат.

Джо Селко цитирует Дэвида Макговерана и К. Дж. Дата:

6 NULL: отсутствуют данные в SQL (185)

В своей книге Руководство по Sybase и SQL Server , Дэвид МакГоверан и C.J. Date сказал: «Это мнение автора, чем NULL, по крайней мере, как в настоящее время определены и реализованы в SQL, гораздо больше проблем, чем они естьстоит и следует избегать; они показывают очень странно и противоречивое поведение и может быть источником ошибок и путаницы. (Обратите внимание, что эти комментарии и критика относятся к любой системе поддерживает NULL в стиле SQL, а не только для SQL Server.) ”

NULLs как наркомания :

(186/187)

В остальной части этой книги, Я буду убеждать вас не использовать их , что может показаться противоречивым, но это не так. Подумайте о NULL как наркотик; используйте это правильно, и это работает для вас, но злоупотребьте этим, и это может разрушить все. Ваша лучшая политика - избегать значений NULL, когда вы можете и используете их правильно, когда нужно.

Мое единственное возражение здесь состоит в том, чтобы "использовать их правильно", что плохо взаимодействует с конкретные реализации реализации.

6.5.1 NULLS в предикатах подзапроса (191/192)

Люди забывают, что подзапрос часто скрывает сравнение с NULL. Рассмотрим эти две таблицы:

...

Результат будет пустым. Это нелогично , но правильно.

(сепаратор)

6.5.2 Стандартные решения SQL (193)

SQL-92 решил некоторые проблемы 3VL (трехзначной логики), добавив новый предикат вида:

<условие поиска> IS [NOT] TRUE | ЛОЖЬ | UNKNOWN

Но UNKNOWN сам по себе является источником проблем, так что C.J. Date, в своей книге, цитируемой ниже, рекомендуется в главе 4.5. Как избежать пустых значений в SQL :

  • Не используйте ключевое слово UNKNOWN ни в каком контексте.

Считать «ВНЕ» на НЕИЗВЕСТНО, также связано ниже.

6,8 NULL и языки хоста (194)

Однако вы должны знать, как обрабатываются значения NULL, когда они имеют быть переданным в хост-программу. Нет стандартного языка хоста для определенное вложение поддерживает NULL, что является еще одним веская причина избегать их использования в схеме базы данных.

(сепаратор) * * 1 242

6.9 Советы по проектированию для NULL (195)

Хорошая идея объявить все ваши базовые таблицы с NOT NULL ограничения на все столбцы, когда это возможно. NULL путают людей кто не знает SQL, и NULL стоят дорого.

Возражение: NULL сбивает с толку даже людей, которые хорошо знают SQL, см. ниже.

(195)

В ИНОСТРАННЫХ КЛЮЧАХ следует избегать NULL. SQL позволяет это «преимущество сомнений », но это может привести к потере информации в запросы, которые включают соединения. Например, учитывая код номера детали в Запас, на который ссылается как НАРУЖНЫЙ КЛЮЧ в таблице заказов, вы будут проблемы с получением списка частей, которые имеют NULL. Это обязательные отношения; Вы не можете заказать деталь, которая не существует.

(сепаратор) * * тысяча двести пятьдесят восемь

6.9.1. Избегание пустых значений из программ хоста (197)

Вы можете избежать помещения NULL в базу данных из программ хоста. с некоторой дисциплиной программирования.

...

  1. Определите влияние отсутствующих данных на программирование и отчетность: Числовые столбцы с NULL являются проблемой, потому что запросы Использование агрегатных функций может привести к ошибочным результатам.

(сепаратор) * +1273 *

(227)

SUM () пустого набора всегда NULL. Один из самых распространенных ошибки программирования, сделанные при использовании этого трюка, это написать запрос, который может вернуть более одного ряда. Если вы не думаете об этом, вы можете написал последний пример как: ...

(сепаратор) * +1281 *

10.1.1 Источники NULL (242)

Важно помнить, где могут появляться значения NULL. Они более простовозможное значение в столбце . Агрегатные функции на пустых множествах, ВНЕШНИЕ СОЕДИНЕНИЯ, арифметические выражения с NULL и операторы OLAP все возвращают NULL. Эти конструкции часто отображаются в виде столбцов в Views.

(сепаратор) * * тысяча двести девяносто один

* * 1 293 (301) * * тысяча двести девяносто четыре

Другая проблема с NULL обнаруживается при попытке преобразования Предикаты IN для предикатов EXISTS.

(сепаратор) * +1299 *

16.3 Функции предиката и экстремума ALL (313)

Поначалу нелогично, что эти два предиката не совпадают в SQL:

...

Но вы должны помнить правила для функций экстремумов - они отбросьте все NULL перед возвратом больших или меньших значений. ВСЕ предикат не сбрасывает значения NULL, поэтому вы можете получить их в результатах.

(сепаратор) * +1311 *

(315)

Однако определение в стандарте сформулировано в отрицательно, так что NULL получают преимущество сомнения. ...

Как видите, в UNIQUE стоит избегать значений NULL. ограничения.

Обсуждение ГРУППЫ ПО:

NULL обрабатываются так, как будто они все равны друг другу , и сформировать свою собственную группу. Каждая группа затем сводится к одному строка в новой таблице результатов, которая заменяет старую.

Это означает, что для предложения GROUP BY NULL = NULL не оценивать в NULL, как в 3VL, но в TRUE.

Стандарт SQL сбивает с толку:

ORDER BY и NULL (329)

Считается ли значение ключа сортировки, равное NULL, большим или меньшим, чем ненулевое значение определяется реализацией, но ...

... Существуют продукты SQL, которые делают это в любом случае.

В марте 1999 года Крис Фаррар поднял вопрос от одного из своих разработчики, которые заставили его изучить часть стандарта SQL, которая Я думал, что понял . Крис обнаружил некоторые различия между общее понимание и фактическая формулировка спецификации .

И так далее. Я думаю, что достаточно Celko.

C. J. Дата в SQL NULL

C. J. Дата более радикальна в отношении NULL: избегайте NULL в SQL, точка. Фактически, глава 4 его SQL и реляционной теории: как писать точно Код SQL озаглавлен «НЕТ ДУБЛИКАТОВ, НЕТ НУЛЕЙ», с подразделами "4.4 Что не так с NULL?" и "4.5 Как избежать NULL в SQL" (перейдите по ссылке: благодаря Google Книгам вы можете читать некоторые страницы в Интернете).

Фабиан Паскаль на пустых значениях SQL

Из его Практические вопросы в управлении базами данных - Справочник для практикующего мышления (нет выдержек в Интернете, извините):

10.3 Практические последствия

10.3.1 SQL NULL

... SQL страдает от проблем, присущих 3VL, а также от многих причуды, осложнения, нелогичность и прямые ошибки [10, 11]; среди них следующие:

  • Агрегатные функции (например, SUM (), AVG ()) игнорируют NULL (за исключением COUNT ()).
  • Скалярное выражение в таблице без строк неправильно оценивается как NULL вместо 0.
  • Выражение "NULL = NULL" оценивается как NULL, но на самом деле недопустимо в SQL; тем не менее ORDER BY обрабатывает значения NULL как равные (независимо от того, предшествуют они или следуют «обычным» значениям, остается поставщик СУБД).
  • Выражение «x IS NOT NULL» не равно «NOT (x IS NULL)», как в случае с 2VL.

...

Все коммерчески реализуемые диалекты SQL следуют этому подходу 3VL, и, таким образом, они не только демонстрируют эти проблемы, но и имеют специальную реализацию проблемы, которые различаются по продуктам .

8 голосов
/ 04 декабря 2009

Возможно, это зависит, но я подумал, что NULL=NULL оценивается как NULL, как и большинство операций с NULL в качестве операнда.

7 голосов
/ 04 декабря 2009

То, что вы не знаете, что такое две вещи, не означает, что они равны. Если, когда вы думаете о NULL, вы думаете о «NULL» (строка), то вам, вероятно, нужен другой тест на равенство, такой как IS DISTINCT FROM AND IS NOT DISTINCT FROM

в Postgresql

Из документов PostgreSQL по «Функции сравнения и операторы»

выражение IS DISTINCT FROM выражение

выражение IS NOT DISTINCT FROM выражение

Для ненулевых входов IS DISTINCT FROM совпадает с оператором <>. Тем не менее, если оба входа имеют значение null, он возвращает false, а если только один вход имеет значение null, он возвращает true. Точно так же IS NOT DISTINCT FROM идентичен = для ненулевых входов, но он возвращает истину, когда оба входа нулевые, и ложь, если только один вход нулевой. Таким образом, эти конструкции эффективно действуют так, как если бы null был обычным значением данных, а не «неизвестным».

4 голосов
/ 06 февраля 2014

В technet есть хорошее объяснение того, как работают нулевые значения.

Нуль означает неизвестность.

Следовательно, логическое выражение

значение = ноль

не оценивается как ложное, оно оценивается как нулевое, но если это конечный результат предложения where, то ничего не возвращается. Это практичный способ сделать это, так как возвращать ноль было бы трудно для зачатия.

Интересно и очень важно понять следующее:

Если в запросе у нас есть

where (value=@param Or @param is null) And id=@anotherParam

и

  • значение = 1
  • @ param is null
  • id = 123
  • @ anotherParam = 123

тогда

"value = @ param" оценивается как ноль
"@param is null" имеет значение true
"id = @ anotherParam" оценивается как true

Таким образом, вычисляемое выражение становится

(ноль или правда) и правда

У нас может возникнуть искушение подумать, что здесь "null Or true" будет оцениваться как null, и, таким образом, все выражение станет нулевым, и строка не будет возвращена.

Это не так. Зачем?

Поскольку "null Or true" оценивается как true, что очень логично, поскольку, если один операнд является истинным с оператором Or, тогда независимо от значения другого операнда операция вернет true. Таким образом, не имеет значения, что другой операнд неизвестен (ноль).

Итак, мы наконец имеем true = true, и, таким образом, строка будет возвращена.

Примечание: с той же кристально чистой логикой, что "null Or true" оценивается как true, "null And true" оценивается как null.

Обновление:
Хорошо, просто чтобы завершить, я хочу добавить сюда и остальное, что довольно забавно по отношению к вышесказанному.

"null Or false" оценивается как null, "null And false" оценивается как false. :)

Логика, конечно, все так же самоочевидна, как и раньше.

4 голосов
/ 07 октября 2010

Понятие NULL сомнительно, если не сказать больше. Кодд представил реляционную модель и концепцию NULL в контексте (и продолжил предлагать более одного вида NULL!) Однако, реляционная теория эволюционировала со времени первоначальных работ Кодда: некоторые из его предложений с тех пор были отброшены (например, первичный ключ) и другие никогда не завоевывали популярность (например, тета-операторы). В современной теории отношений (истинно теории отношений, я должен подчеркнуть), NULL просто не существует. Смотрите Третий Манифест. http://www.thethirdmanifesto.com/

Язык SQL сталкивается с проблемой обратной совместимости. NULL нашел свой путь в SQL, и мы застряли с ним. Возможно, реализация NULL в SQL несовершенна (реализация SQL Server еще более усложняет ситуацию из-за опции ANSI_NULLS).

Я рекомендую избегать использования столбцов NULLable в базовых таблицах.


Хотя, возможно, мне не следует поддаваться искушению, я просто хотел заявить о своих собственных исправлениях относительно того, как NULL работает в SQL:

NULL = NULL оценивается как UNKNOWN.

UNKNOWN - логическое значение.

NULL - это значение данных.

Это легко доказать, например.

SELECT NULL = NULL

правильно генерирует ошибку в SQL Server. Если бы результат был значением данных, то мы ожидали бы увидеть NULL, поскольку некоторые ответы здесь (ошибочно) предполагают, что мы бы.

Логическое значение UNKNOWN обрабатывается по-разному в SQL DML и SQL DDL соответственно.

В SQL DML UNKNOWN приводит к удалению строк из набора результатов.

Например:

CREATE TABLE MyTable
(
 key_col INTEGER NOT NULL UNIQUE, 
 data_col INTEGER
 CHECK (data_col = 55)
);

INSERT INTO MyTable (key_col, data_col)
   VALUES (1, NULL);

INSERT успешно выполняется для этой строки, хотя условие CHECK разрешается до NULL = NULL. Это обусловлено стандартом SQL-92 («ANSI»):

11.6 Определение ограничения таблицы

3)

Если ограничение таблицы является проверкой определение ограничения, тогда пусть SC будет условие поиска немедленно содержится в проверочном ограничении определение и пусть T будет именем таблицы включены в соответствующую таблицу дескриптор ограничения; стол ограничение не выполняется, если и только если

СУЩЕСТВУЮЩИЙ (SC))

верно.

Прочтите это снова внимательно, следуя логике.

На простом английском языке нашей новой строке выше дано «преимущество сомнения» о том, что он UNKNOWN и ему разрешено пройти.

В SQL DML гораздо проще следовать правилу для предложения WHERE:

Условие поиска применяется к каждый ряд Т. Результат где предложение является таблицей этих строк T для которого результат поиска условие верно.

На простом английском языке строки, которые оцениваются как UNKNOWN, удаляются из набора результатов.

4 голосов
/ 04 декабря 2009

NULL не равно ничему, даже самому себе. Мое личное решение для понимания поведения NULL - избегать его максимального использования:).

3 голосов
/ 28 марта 2014

Путаница возникает из-за уровня косвенности (абстракции), возникающего при использовании NULL .

Возвращаясь к аналогии «что под елкой», «Неизвестно» описывает состояние знания о том, что находится в коробке А.

Так что, если вы не знаете, что находится в коробкеО, вы говорите, что это «Неизвестно», но это не означает, что «Неизвестно» находится внутри поля .В коробке есть что-то, кроме неизвестного, возможно, какой-то объект, или, возможно, ничего нет в коробке.

Точно так же, если вы не знаете, что находится во вставке B, вы можете пометить свой уровень знаний о содержимом как «Неизвестный».

Итак, вот кикер: ваш уровень знаний о Box A равен вашему состоянию знаний о Box B .(Уровень ваших знаний в обоих случаях - «Неизвестно» или «Я не знаю, что находится в коробке».) Но содержимое коробок может совпадать или не совпадать.

Возвращаясь к SQL, в идеале вы сможете сравнивать значения только тогда, когда знаете, что это такое. К сожалению, метка, описывающая недостаток знаний, хранится в самой ячейке , поэтому мы склонны использовать ее в качестве значения.Но мы не должны использовать это как значение, потому что это привело бы к тому, что «содержимое блока A равно содержимому блока B, когда мы не знаем, что находится в блоке A, и / или мы не знаем, что находится в блоке B.(Логично, что «если я не знаю, что находится во врезке А, и если я не знаю, что находится во врезке В, то, что находится во врезке А = что в ящике В», неверно.)

YayМертвая Лошадь.

3 голосов
/ 17 мая 2012

Поскольку NULL означает «неизвестное значение», и два неизвестных значения не могут быть равны.

Итак, если по нашей логике NULL N ° 1 равно NULL N ° 2, то мы должны это как-то сказать:

SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)

, где известное значение -1 N ° 1 равно -1 N ° 2

...