Почему NOT IN с набором, содержащим NULL, всегда возвращает FALSE / NULL?

21

У меня был запрос (для Postgres и Informix) с NOT INпредложением, содержащим подзапрос, который в некоторых случаях возвращал NULLзначения, в результате чего это предложение (и весь запрос) ничего не возвращало.

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

newenglander
источник

Ответы:

29

Булева логика - или Трехзначная логика

  • IN является сокращением для ряда условий ИЛИ
  • x NOT IN (1, 2, NULL) такой же как NOT (x = 1 OR x = 2 OR x = NULL)
  • ... такой же как x <> 1 AND x <> 2 AND x <> NULL
  • ... так же, как true AND true AND unknown**
  • ... = unknown**
  • ... что почти так же, как falseв этом случае, поскольку оно не пройдет WHEREусловие **

Вот почему люди используют EXISTS+, NOT EXISTSа не IN+ NOT IN. Также см . Использование логики НЕ по отношению к индексам для более подробной информации.

** Примечание: unknownтакое же, как falseв конце выражения в WHEREусловии.
Пока выражение оценивается, оно неизвестно.
См. Комментарий @ kgrittn ниже, почему

ГБН
источник
10
Даже с разъяснениями это технически неправильно, и таким образом, что может кого-то сжечь. Например, если вы видите x <> NULLразрешение FALSE, вы можете рассчитывать NOT (x <> NULL)на оценку TRUE, а это не так. Оба оценивают UNKNOWN. Хитрость заключается в том, что строка выбирается только в том случае, если WHEREпредложение (если присутствует) оценивается как TRUE- строка опускается, если предложение оценивается либо в, FALSEлибо в UNKNOWN. Такое поведение (в целом и для NOT INпредиката в частности) предписывается стандартом SQL.
кгритт
Также NULL NOT IN (some_subquery)не должен возвращать внешнюю строку, кроме случаев, когда some_subqueryне возвращает никаких строк. Вот почему план выполнения, когда оба столбца имеют нулевое значение, может быть значительно дороже. Пример SQL Server
Мартин Смит