SQL Server: ¿Por qué la comparación nulo = valor devuelve verdadero para NOT IN?

¿Por qué la comparación devalue anull devuelve falso, excepto cuando se usa unNOT IN, donde vuelve cierto?

Dada una consulta para encontrar todos los usuarios de stackoverflow quetener una publicación:

SELECT * FROM Users
WHERE UserID IN (SELECT UserID FROM Posts)

Esto funciona como se esperaba; Recibo una lista de todos los usuarios que tienen una publicación.

Ahora consulta por el inverso; encontrar todos los usuarios de stackoverflow queno lo hagas tener una publicación:

SELECT * FROM Users
WHERE UserID NOT IN (SELECT UserID FROM Posts)

Esto no devuelve registros, lo cual es incorrecto.

Datos hipotéticos dados1

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...
                   ...      ... 

Y asuma las reglas de NULL:

NULL = NULL evalúa a desconocidoNULL <> NULL evalúa a desconocidovalue = NULL evalúa desconocido

Si miramos la segunda consulta, estamos interesados en encontrar todas las filas donde está el Users.UserIDno encontrado en la columna Posts.UserID. procedería lógicamente de la siguiente manera:

Verificar ID de usuario 1

1 = 1 devuelve verdadero Por lo tanto, concluimos que este usuario tiene algunas publicaciones y no las incluimos en la lista de resultados

Ahora verifique el ID de usuario 2:

2 = 1 devuelve falso, así que seguimos buscando2 = 2 devuelve verdadero, por lo que concluimos que este usuario tiene algunas publicaciones y no las incluimos en la lista de resultados

Ahora verifique el ID de usuario 399573

399573 = 1 devuelve falso, así que seguimos buscando399573 = 2 devuelve falso, así que seguimos buscando...399573 = null vuelve desconocido, así que seguimos buscando...

No encontramos publicaciones de UserID 399573, por lo que lo incluiríamos en la lista de resultados.

Excepto que SQL Server no hace esto. Si tiene un NULL en suin lista, de repente encuentra una coincidencia.De repente encuentra una coincidencia. Repentinamente399573 = null se evalúa como verdadero

¿Por qué la comparación devalue anull volver desconocido, excepto cuando devuelve verdadero?

Editar: sé que puedo solucionar estoabsurdo comportamiento excluyendo específicamente los nulos:

SELECT * FROM Users
WHERE UserID NOT IN (
   SELECT UserID FROM Posts
   WHERE UserID IS NOT NULL)

Pero no debería tener que hacerlo, por lo que puedo decir, la lógica booleana debería estar bien sin ella, de ahí mi pregunta.

$45 a46$celko ahora tiene su propia etiqueta

Respuestas a la pregunta(2)

Su respuesta a la pregunta