Почему NULL = NULL оценивается как ложное в SQL-сервере


147

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


166
У меня нет сестры и моего друга. Если «NULL = NULL», то у нас есть общая сестра, и поэтому мы связаны! :)
Мэтт Гамильтон

11
В отношении пустых значений SQL существует длительная дискуссия (см., Например: en.wikipedia.org/wiki/Null_%28SQL%29#Controversy и firstsql.com/inulls.htm ). Конкретный момент здесь заключается в том, что равенство является давно установленной математической концепцией, и SQL нарушает его - равенство является рефлексивным: для каждого x, x = x. Это всегда должно быть правдой, иначе кто-то вводит интерпретацию равенства, которая не является стандартной, и путаница является очевидным результатом.
MaD70

14
Это не нарушает математику вообще. Я думаю о двух числах. Я не собираюсь говорить вам, что они, хотя. Итак, теперь вы говорите мне, они равны?
Том Х

10
@ Матт, я не согласен с твоей аналогией. NULL = NULL не означает, что у вас есть общая сестра, это будет означать, что у вас обоих нет сестры.
reustmd

5
@ manu08 Нет, текущая реализация (эта NULL никогда не равна NULL) означает, что у нас обоих нет сестры, и это была моя точка зрения.
Мэтт Гамильтон

Ответы:


206

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

РЕДАКТИРОВАТЬ: Это зависит от вашей настройки 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'

11
x = x выполняется только тогда, когда x является известным значением. NULL - это текстовое представление неизвестного значения. Если у вас есть два неизвестных значения, вы не сможете окончательно сказать что-либо об их равенстве. Я полагаю, что это также сохранялось в течение нескольких веков.
Дьюэйн Кристенсен

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

5
SQL NULL ничем не отличается от IEEE с плавающей точкой NaN, где у вас также есть (NaN == NaN) == false && (NaN != Nan) == false && (NaN < NaN) == false && ...- потому что, ну, если это не число, вы просто не можете много говорить об этом; это что-то неизвестное. Эта концепция является разумной, даже если она не понятна людям, которые никогда ее не видели.
Павел Минаев

8
Здесь нет нарушения рефлексивности, потому что NULL не является членом набора значений (домен, в терминах отношений). NULL не является значением . Это заполнитель для значения, которое неизвестно.
Павел Минаев

9
Другими словами, каждое NULLвыражение SQL может рассматриваться как отдельная математическая переменная. Таким образом, выражение NULL = NULLдолжно рассматриваться как x = y, где xи yявляются несвязанными переменными. Теперь, если кто-то спросит вас, какова ценность x = y? Единственный разумный ответ - «некоторые z». Таким образом , у нас есть (x = y) = z- или, транскрибировать его обратно в SQL, (NULL = NULL) = NULL.
Павел Минаев

131

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

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

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

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


4
Я не согласен, что нуль означает «неизвестный». Что это на самом деле означает «нет данных». Это может быть использовано для представления случая, когда информация неизвестна, но на самом деле она более вероятна для указания того, что что-то не существует. Чтобы продолжить ваш пример: Какое отчество Фрэнк? У него его нет (ноль). Какое второе имя у Ширли? У нее ее нет (ноль). У Фрэнка и Ширли одно и то же второе имя? Да? Нет? Не знаю? Я вижу аргумент для «нет», и я вижу аргумент для «не знаю», но нет реального аргумента для «да», если вы не слишком буквально.
Richiban

2
@richiban Я не согласен. Отсутствие строки означает «нет данных»
Нил Макгиган

1
@NeilMcGuigan Это верно, если для данных, которые имеют свою собственную таблицу, но как насчет данных, представленных в столбце? Разве вы не использовали бы «ноль» для представления факта, что данные не существуют? «Неизвестно» является очень конкретной причиной отсутствия данных.
Richiban

3
Но null = nullуступает FALSE, а не NULL.
Слартидан

1
@slartidan Я согласен с вами, однако это неверно
Нил МакГиган

28

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

Это 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 (в действительности это семейство логик) - это гораздо более свежая разработка (но я не уверен, когда она была впервые разработана).

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


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

Джо Селко о SQL NULL

Я вижу, Джо Селко часто цитируется на этом форуме. Видимо, он очень уважаемый автор здесь. Итак, я сказал себе: «что он пишет о 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 190
NULL и логики 190
6.5.1 NULL в подзапросе Предикаты 191
6.5.2 Стандарт Решения SQL 193
6.6 Math и NULL 193
6.7 Функции и NULL 193
6.8 NULL и языки хоста 194
6.9 Советы по проектированию для NULL 195
6.9.1 Избегание NULL из программ хоста 197
6.10 Замечание о множественных значениях NULL 198
10.1 IS NULL Predicate 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). Некоторые реализации SQL возвращают сообщение об ошибке, некоторые возвращают NULL и DB2 / 400; версия 3, выпуск 1 вернул * NEGINF (сокращение от «минус бесконечность») в качестве результата.

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

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

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

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

(186/187)

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

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

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

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

...

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

(разделитель)

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

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

<условие поиска> IS [NOT] TRUE | ЛОЖЬ | НЕИЗВЕСТНЫЙ

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

  • Не используйте ключевое слово НЕИЗВЕСТНО в любом контексте.

Прочитайте «ВНУТРИ» на НЕИЗВЕСТНОМ, также связанном ниже.

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

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

(разделитель)

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

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

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

(195)

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

(разделитель)

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

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

...

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

(разделитель)

(227)

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

(разделитель)

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

Важно помнить, где могут быть значения NULL. Они больше, чем просто возможное значение в столбце . Агрегатные функции для пустых множеств, OUTER JOIN, арифметические выражения с NULL и операторы OLAP возвращают NULL. Эти конструкции часто отображаются в виде столбцов в VIEW.

(разделитель)

(301)

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

(разделитель)

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

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

...

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

(разделитель)

(315)

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

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

Обсуждение GROUP BY:

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

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

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

ORDER BY и NULL (329)

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

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

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

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

Дата CJ на пустых значениях SQL

CJ Date более радикально относится к NULL: избегайте NULL в SQL, точка. Фактически, глава 4 его теории SQL и реляционной теории: как писать точный код SQL называется «NO DUPLICATES, NO NULLS», с подразделами «4.4. Что не так с NULL?» и «4.5 Избегание пустых значений в SQL» (перейдите по ссылке: благодаря Google Книгам вы можете читать некоторые страницы в режиме онлайн).

Фабиан Паскаль о SQL NULL

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

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, и, таким образом, они не только демонстрируют эти проблемы, но также имеют специфические проблемы реализации, которые различаются в разных продуктах .


4
«И это была моя точка зрения: NULL, как значение, является« странным зверем »». - это потому, что NULLэто не ценность.
Павел Минаев

1
Также SQL Server не дает (NULL = NULL) -> FALSE. Чтобы процитировать документацию для ANSI_NULLS: «Когда указано ON, все сравнения с нулевым значением оцениваются как UNKNOWN . Если задано OFF, сравнение не-UNICODE значений с нулевым значением оценивается как TRUE, если оба значения равны NULL.»
Павел Минаев

@ Павел Минаев: а) и насколько ИСТИНА лучше, чем ЛОЖЬ? б) Если это не значение, почему оно присваивается как часть значений переменных?
MaD70

1
>> Так как это декабрь, давайте использовать сезонный пример. У меня есть два подарка под елкой. Теперь скажите мне, если у меня есть два одинаковых или нет. ..... да, вы сделали, поскольку у вас есть две вещи, и, насколько вы сейчас обеспокоены , насколько вам известно, они абсолютно одинаковы для вас
Брэд Томас,

3
null = null должен быть истинным. нуль корректно определено значение , которое может представлять собой неизвестное значение, но оно может также представлять в отсутствие числа. Разработчик должен решить, что представляет собой ноль, но сам ноль является абсолютно значением, а нуль равен нулю = нуль. Любая другая реализация обречена на бедствие, потому что вы вставляете троичную логику в предикаты, которые по сути являются логическими. Я поражен, что это становится постоянным при настройке в SQL-сервере. ВЫКЛ ВЫКЛ ВЫКЛ с ним.
Трийнко


9

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

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

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

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

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


5

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

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

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


Хотя, возможно, я не должен поддаваться искушению, я просто хотел заявить о своих собственных исправлениях о том, как 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 будет именем таблицы, включенным в соответствующий дескриптор ограничения таблицы; ограничение таблицы не выполняется тогда и только тогда, когда

СУЩЕСТВУЕТ (ВЫБЕРИТЕ * ОТ Т, ГДЕ (СЦ)

правда.

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

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

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

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

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


5

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

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

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

значение = NULL

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

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

Если в запросе мы имеем

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

и

  • Значение = 1
  • @param is null
  • ID = 123
  • @ AnotherParam = 123

затем

"value = @ param" оценивается как нулевое
"@param is null" оценивается как истинное
"id = @ anotherParam" оценивается как истинное

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

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

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

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

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

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

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

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

«ноль или ложь» оценивается как ноль, «ноль и ложь» оценивается как ложь. :)

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


4

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

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

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

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


nullParam1 = -1и nullParam2 =NULLи авиакатастрофа .... должно бытьISNULL(NULLIF(@nullParam1, @nullParam2), NULLIF(@nullParam2, nullParam1)) IS NULL
Selvin

4

Все ответы здесь, кажется, приходят с точки зрения CS, поэтому я хочу добавить один с точки зрения разработчика.

Для разработчика NULL очень полезен. Ответы здесь говорят, что NULL означает неизвестный, и, возможно, в теории CS это правда, не помню, это было давно. В реальной разработке, хотя, по моему опыту, это происходит примерно в 1% случаев. Остальные 99% используются в тех случаях, когда значение не UNKNOWN, но оно известно, чтобы быть отсутствующим.

Например:

  • Client.LastPurchase, для нового клиента. Не известно, известно, что он еще не совершил покупку.

  • При использовании ORM с отображением « Таблица на иерархию классов» некоторые значения просто не отображаются для определенных классов.

  • При отображении древовидной структуры корень обычноParent = NULL

  • И многое другое ...

Я уверен, что большинство разработчиков в какой-то момент написали WHERE value = NULL, не получили никаких результатов, и именно так они узнали о IS NULLсинтаксисе. Посмотрите, сколько голосов имеют этот вопрос и связанные с ним.

Базы данных SQL являются инструментом, и они должны быть спроектированы так, чтобы их пользователям было проще понять.


1
Все, кажется, кричат ​​«NULL неизвестно», а затем оправдывают свое поведение. Да, если это предпосылка, то 3VL может быть ответ. Но почти во всех БД, над которыми я работаю, NULL означает отсутствие. Извините, что ваш голос потерян в пустыне @AlexDev
Джон Рис

3

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


1
может быть равно всем, как в случае левого / правого / внешнего соединения ...
Мигель Вентура

5
Какой глупый непродуктивный ответ. То же самое можно сказать элементарным детям об алгебре, но без фактического признания того, что пытается решить ее, это может показаться глупым, что она и сделала.
Эван Кэрролл

2
@Evan: На самом деле, избегать NULL - это разумное решение. 3-значная логика не бесспорная, и многие люди считают , что SQL будет лучше без NULL и все (необходимых) сложности это влечет за собой.
Слеське

3
«Многие люди» - это ласковое слово, а «не бесспорный» - способ скрыть более простую «спорную», которой не является 3VL.
Эван Кэрролл

«NULL не равен ничему, даже самому себе». исходя из этой логики, <somevalue>! = NULL должно возвращать true. Однако в странной вселенной SQL это неверно.
Том Линт

3

Вопрос:
одно неизвестное равно другому неизвестному?
(NULL = NULL) На
этот вопрос никто не может ответить, поэтому по умолчанию он имеет значение true или false, в зависимости от настроек ansi_nulls.

Однако вопрос:
эта неизвестная переменная неизвестна?
Этот вопрос совершенно другой, и на него можно ответить правдиво.

nullVariable = null сравнивает значения
nullVariable is null сравнивает состояние переменной


3

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

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

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

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

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

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

Yay, Dead Horse.


3

У MSDN есть хорошая описательная статья о нулях и логике трех состояний, которую они порождают.

Вкратце, спецификация SQL92 определяет NULL как неизвестный, а NULL, используемый в следующих операторах, приводит к непредвиденным результатам для непосвященных:

= operator NULL   true   false 
NULL       NULL   NULL   NULL
true       NULL   true   false
false      NULL   false  true

and op     NULL   true   false 
NULL       NULL   NULL   false
true       NULL   true   false
false      false  false  false

or op      NULL   true   false 
NULL       NULL   true   NULL
true       true   true   true
false      NULL   true   false

Но вопрос не о 3VL (трехзначной логике), а о рефлексивном свойстве равенства.
MaD70

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

1

null неизвестен в sql, поэтому мы не можем ожидать, что два неизвестных будут одинаковыми.

Однако вы можете получить такое поведение, установив для ANSI_NULLS значение Выкл. (По умолчанию включено). Вы можете использовать оператор = для нулей.

SET ANSI_NULLS off
if null=null
print 1
else 
print 2
set ansi_nulls on
if null=null
print 1
else 
print 2

2
Это все виды нет . У мира есть определение null, научитесь понимать его или просто измените таблицу, чтобы иметь типы int, и обновите столбцы.
Эван Кэрролл

3
Я действительно не рекомендовал выключать SET ANSI_NULLS. Я узнал о ANSI_NULLS трудным путем. Но всегда полезно знать все доступные опции, особенно когда вы сталкиваетесь с строкой, в которой говорится, где SomeId = null. Как бы вы понимали эту строку, не зная ANSI_NULLS. Как я выгляжу, мой пост был полезен .. :)
пс.

1

Вы работаете на правительство, регистрируя информацию о гражданах. Это включает в себя национальный идентификатор для каждого человека в стране. Около 40 лет назад у дверей церкви остался ребенок, никто не знает, кто их родители. Этого человека отец удостоверение личности NULL. Два таких человека существуют. Подсчитайте людей, которые имеют одинаковый идентификатор отца, по крайней мере, с одним другим человеком (людьми, которые являются братьями и сестрами). Ты тоже считаешь этих двоих?

Ответ - нет, вы не знаете, потому что мы не знаем, являются ли они братьями и сестрами или нет.

Предположим, у вас нет NULLопции, и вместо этого вы используете какое-то заранее определенное значение для представления «неизвестного», возможно, пустой строки или цифры 0 или символа * и т. Д. Тогда в ваших запросах будет иметь значение * = * , 0 = 0, и «» = «» и т. Д. Это не то, что вы хотите (в соответствии с примером выше), и как вы часто можете забыть об этих случаях (пример выше - это очевидный случай вне обычного повседневного мышления). ), тогда вам нужен язык, чтобы помнить для вас, что NULL = NULLэто не так.

Голь на выдумки хитра.


0

Просто дополнение к другим замечательным ответам:

AND: The result of true and unknown is unknown, false and unknown is false,
while unknown and unknown is unknown.

OR: The result of true or unknown is true, false or unknown is unknown, while unknown or unknown is unknown.

NOT: The result of not unknown is unknown

0

Если вы ищете выражение, возвращающее true для двух NULL, вы можете использовать:

SELECT 1 
WHERE EXISTS (
    SELECT NULL
    INTERSECT
    SELECT NULL
)

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


0

Например, тест на равенство в операторе case, когда предложение может быть изменен с

XYZ = NULL 

в

XYZ IS NULL

Если я хочу обработать пробелы и пустую строку как равные NULL, я часто также использую тест на равенство:

(NULLIF(ltrim( XYZ ),'') IS NULL)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.