Почему сравнение value
с null
возвращает false, кроме случаев, когда используется NOT IN
, где он возвращает true?
Учитывая запрос, чтобы найти всех пользователей stackoverflow, у которых есть сообщение:
SELECT * FROM Users
WHERE UserID IN (SELECT UserID FROM Posts)
Это работает так, как ожидалось; Я получаю список всех пользователей, у которых есть сообщение.
Теперь запрос для обратного; найти всех пользователей stackoverflow, у которых не есть сообщение:
SELECT * FROM Users
WHERE UserID NOT IN (SELECT UserID FROM Posts)
Это не возвращает никаких записей, что неверно.
Данные гипотетические данные 1
Users Posts
================ ===============================
UserID Username PostID UserID Subject
------ -------- ------- ------ ----------------
1 atkins 1 1 Welcome to stack ov...
2 joels 2 2 Welcome all!
... ... ... ...
399573 gt6989b ... ...
... ... ... ...
10592 null (deleted by nsl&fbi...
... ...
И принимаем правила NULL:
-
NULL = NULL
оценивается как неизвестный -
NULL <> NULL
оценивается как неизвестный -
value = NULL
оценивает неизвестные
Если мы посмотрим на второй запрос, нам будет интересно найти все строки, в которых идентификатор не находится в столбце Posts.UserID. я буду действовать логически следующим образом:
Проверить UserID 1
-
1 = 1
возвращает true. Поэтому мы заключаем, что у этого пользователя есть несколько сообщений и не включают их в выходной список
Теперь проверьте UserID 2:
-
2 = 1
возвращает false, поэтому мы продолжаем искать -
2 = 2
возвращает true, поэтому мы заключаем, что у этого пользователя есть несколько сообщений и не включать их в выходной список
Теперь проверьте UserID 399573
-
399573 = 1
возвращает false, поэтому мы продолжаем искать -
399573 = 2
возвращает false, поэтому мы продолжаем искать - ...
-
399573 = null
возвращает неизвестный, поэтому мы продолжаем искать - ...
Мы не нашли сообщений от UserID 399573, поэтому мы включили бы его в выходной список.
Кроме того, SQL Server этого не делает. Если у вас есть NULL в вашем списке in
, тогда он находит совпадение. Он неожиданно находит матч. Внезапно 399573 = null
оценивается как true.
Почему сравнение value
с null
возвращает неизвестно, кроме случаев, когда оно возвращает true?
Изменить: я знаю, что могу обойти это поведение бессмысленного, специально исключив нули:
SELECT * FROM Users
WHERE UserID NOT IN (
SELECT UserID FROM Posts
WHERE UserID IS NOT NULL)
Но мне не нужно, насколько я могу сказать, логическая логика должна быть в порядке без него - следовательно, мой вопрос.
Сноски
- 1 гипотетические данные; если вам это не нравится: составьте ваш.
- celko теперь имеет свой собственный тег