SQL: почему значения NULL отфильтровываются в предложении where? - PullRequest
5 голосов
/ 26 марта 2009

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

И другой разработчик, и я согласны с тем, что NULL <> 1 ... Это ошибка в SQL или она была разработана таким образом? Похоже на недостаток дизайна.

Текущий код:

(VoidedIndicator <> 1)

Предлагаемое исправление:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)

Разъяснение (Джон Эриксон)

VoidedIndicator - это обнуляемое битовое поле, поэтому он может иметь следующие значения: NULL, 0 или 1

Когда оператор SQL создается с предложением where, например (VoidedIndicator <> 1), мы получаем только те записи, которые имеют VoidedIndicator == 0, но мы ожидали, что VoidedIndicator == 0 и VoidedIndicator IS NULL. Почему это?

Ответы [ 7 ]

12 голосов
/ 26 марта 2009

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

Для SQL Null НЕ означает «Нет значения», это означает «Неизвестное значение»

Имея это в виду, рассмотрите ответ на вопрос, который вы задаете SQL, на простом английском языке.

Q: Is this unknown value not equal to 1? 
A: I don't know, there is no way to tell without knowing the value.

Hence Null<>1 = Null
11 голосов
/ 26 марта 2009

Из записи Википедии о NULL :

Например, предложение WHERE или условное утверждение может сравнить значение столбца с константой. это часто ошибочно полагал, что пропущенное значение будет «меньше чем» или "не равно" константе, если это поле содержит Null, но, на самом деле, такие выражения возвращают Unknown. Пример ниже:

-- Rows where num is NULL will not be returned,
-- contrary to many users' expectations.
SELECT * FROM sometable WHERE num <> 1;   

По сути, любое сравнение между NULL и чем-то еще, будь то с = или <>, не будет истинным.

В качестве другой ссылки на странице MSDN T-SQL в <> говорится:

Сравнивает два выражения (сравнение оператор). Когда вы сравниваете ненулевой выражений, результат ИСТИНА, если левый операнд не равен правому операнд; в противном случае результат ЛОЖНЫЙ. Если один или оба операнда NULL, см. SET ANSI_NULLS (Transact-SQL).

Страница SET ANSI_NULLS затем сообщает:

Когда SET ANSI_NULLS включен, SELECT оператор, который использует WHERE имя_ столбца = NULL возвращает ноль строк, даже если в column_name есть нулевые значения. Оператор SELECT, который использует WHERE column_name <> NULL возвращает ноль строк даже если есть ненулевые значения в column_name.

...

Когда SET ANSI_NULLS включен, все Сравнение с нулевым значением оценить, чтобы НЕИЗВЕСТНО. Когда SET ANSI_NULLS выключен, сравнение всех данные против нулевого значения оценивают в TRUE, если значение данных равно NULL.

3 голосов
/ 26 марта 2009

Это не ошибка.

NULL не равно ничему, даже NULL (NULL = NULL возвращает FALSE).

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

1 голос
/ 26 марта 2009

Другие люди правы, что NULL <> 1 не оценивается как истинное, поэтому оно не удовлетворяет предложению WHERE.

Предложенное вами исправление - лучший способ справиться с ним:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)

SQL-99 имеет предикат, который помогает в этом случае, называется IS DISTINCT FROM:

(VoidedIndicator IS DISTINCT FROM 1)

Этот предикат будет вести себя точно так же, как предложенное вами исправление. К сожалению, Microsoft SQL Server пока не поддерживает IS DISTINCT FROM.

0 голосов
/ 26 марта 2009

NULL <> 1 (теоретически) оценивается как «возможно», что означает, что запись не будет возвращена.

0 голосов
/ 26 марта 2009

Поскольку предложение WHERE выбирает строки только тогда, когда условие оценивается как true.

Когда один из операндов имеет значение NULL, условие обычно оценивается как UNKNOWN (приблизительно эквивалентно NULL) и, следовательно, не является истинным. Это относится как к column = 1, так и к column <> 1; если столбец равен NULL, условие поиска не выполняется.

Именно поэтому вам по возможности избегают столбцов NULL.

0 голосов
/ 26 марта 2009

Вы также можете: isnull (VoidedIndicator, 1) <> 1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...