SQL Server: Por que a comparação null = value retorna true para NOT IN?
Por que a comparação devalue
paranull
retorne false, exceto ao usar umNOT IN
, onde retorna true?
Dada uma consulta para encontrar todos os usuários de stackoverflow queter uma postagem:
SELECT * FROM Users
WHERE UserID IN (SELECT UserID FROM Posts)
Isso funciona como esperado; eu recebo uma lista de todos os usuários que têm uma postagem.
Agora, procure o inverso; encontre todos os usuários de stackoverflow quenão tem uma postagem:
SELECT * FROM Users
WHERE UserID NOT IN (SELECT UserID FROM Posts)
Isso não retorna registros, o que está incorreto.
Dados 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...
... ...
E assuma as regras dos NULLs:
NULL = NULL
avalia como desconhecidoNULL <> NULL
avalia como desconhecidovalue = NULL
avalia desconhecidoSe observarmos a segunda consulta, estaremos interessados em encontrar todas as linhas em que o Users.UserID énão encontrado na coluna Posts.UserID. eu procederia logicamente da seguinte maneira:
Verifique UserID 1
1 = 1
retorna verdadeiro. Concluímos que este usuário tem algumas postagens e não as incluímos na lista de saídaAgora verifique o UserID 2:
2 = 1
retorna false, então continuamos procurando2 = 2
retorna true, então concluímos que esse usuário tem algumas postagens e não as incluímos na lista de saídaAgora verifique o UserID 399573
399573 = 1
retorna false, então continuamos procurando399573 = 2
retorna false, então continuamos procurando...399573 = null
retorna desconhecido, por isso continuamos procurando...Não encontramos nenhuma mensagem pelo UserID 399573, portanto o incluiríamos na lista de saída.
Exceto que o SQL Server não faz isso. Se você tiver um NULL no seuin
lista e, de repente, encontra uma correspondência.De repente, encontra uma correspondência. De repente399573 = null
avalia como verdadeiro.
Por que a comparação devalue
paranull
retornar desconhecido, exceto quando retornar true?
Editar: eu sei que posso solucionar issosem sentido comportamento, excluindo especificamente os nulos:
SELECT * FROM Users
WHERE UserID NOT IN (
SELECT UserID FROM Posts
WHERE UserID IS NOT NULL)
Mas eu não deveria ter que, até onde eu sei, a lógica booleana deve ficar bem sem ela - daí a minha pergunta.
$45 para46$celko agora tem sua própria tag