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 появился собственный тег

Ответы на вопрос(2)

Ваш ответ на вопрос