SQL Server: почему сравнение null = значение возвращает true для NOT IN?
Почему сравнениеvalue
вnull
вернуть false, кроме случаев использованияNOT IN
где он возвращает истину?
Задан запрос, чтобы найти всех пользователей 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
оценивает неизвестноЕсли мы посмотрим на 2-й запрос, нам будет интересно найти все строки, в которых находится User.UserIDне находится в столбце Posts.UserID. я бы поступил логически следующим образом:
Проверьте UserID 1
1 = 1
возвращает истину. Таким образом, мы заключаем, что у этого пользователя есть некоторые сообщения, и не включают их в список вывода.Теперь проверьте 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
оценивает как истинное.
Почему сравнениеvalue
вnull
вернуть неизвестное, кроме случаев, когда оно возвращает истину?
редактироватьЯ знаю, что могу обойти этобессмысленный поведение, специально исключая нули:
SELECT * FROM Users
WHERE UserID NOT IN (
SELECT UserID FROM Posts
WHERE UserID IS NOT NULL)
Но я не должен был, насколько я могу судить, логическая логика должна быть в порядке без нее - отсюда и мой вопрос.
Сноски1 гипотетические данные; если тебе это не нравится, помирись.у celko появился собственный тег