Primeiro um pouco de teoria:Nulo (SQL)
As partes mais importantes para nós do link acima:
Comparações com NULL e a lógica de três valores (3VL)
Como Null não é membro de nenhum domínio de dados, ele não é considerado um "valor", mas sim um marcador (ou espaço reservado) indicando a ausência de valor. Por causa disso, comparações com Null nunca podem resultar em True ou False, mas sempre em um terceiro resultado lógico, Unknown.[8] O resultado lógico da expressão abaixo, que compara o valor 10 com Null, é Unknown:
SELECT 10 = NULL -- Results in Unknown
para que ambas as comparações:
x = NULL
e x <> NULL
avalia como NULL(desconhecido).
O SQL implementa três resultados lógicos, portanto, as implementações do SQL devem fornecer uma lógica especializada de três valores (3VL). As regras que governam a lógica de três valores do SQL são mostradas nas tabelas abaixo (p eq representam estados lógicos)"[9] As tabelas de verdade que o SQL usa para AND, OR e NOT correspondem a um fragmento comum da lógica de três valores de Kleene e Łukasiewicz ( que diferem em sua definição de implicação, no entanto, o SQL não define tal operação).
+---------+-------------+-------------+-------------+-----------+--------+ | p | q | p OR q | p AND q | p = q |p != q | +---------+-------------+-------------+-------------+-----------+--------+ | True | True | True | True | True | False | | True | False | True | False | False | True | | True | Unknown | True | Unknown | Unknown | Unknown| | False | True | True | False | False | True | | False | False | False | False | True | False | | False | Unknown | Unknown | False | Unknown | Unknown| | Unknown | True | True | Unknown | Unknown | Unknown| | Unknown | False | Unknown | False | Unknown | Unknown| | Unknown | Unknown | Unknown | Unknown | Unknown | Unknown| +---------+-------------+-------------+-------------+-----------+--------+
Efeito de Desconhecido nas cláusulas WHERE
A lógica de três valores SQL é encontrada em Data Manipulation Language (DML) em predicados de comparação de instruções e consultas DML. A cláusula WHERE faz com que a instrução DML atue apenas nas linhas para as quais o predicado é avaliado como True.
Então, em resumo:a cláusula WHERE trata NULL como FALSE
Agora, considere um caso mais simples:
SELECT * FROM T1;
| X |
|--------|
| 1 |
| (null) |
e uma consulta:
SELECT * FROM t1 WHERE x IN (1, NULL);
A consulta acima é um atalho para esta:
SELECT * FROM t1
WHERE x = 1
OR x = NULL
Para a segunda linha da tabela
t
( x =NULL) esta condição se parece com:WHERE NULL = 1
OR NULL = NULL
então esta condição para a linha
x=NULL
é avaliado como NULL porque NULL=1
é NULL, NULL=NULL
é NULL e NULL OR NULL
também é NULL (veja a tabela 3VL acima). Agora considere um caso mais curioso:
SELECT * FROM t1 WHERE x NOT IN (1, NULL);
Esta cláusula
x NOT IN (1, NULL)
é equivalente a NOT ( x IN (1, NULL) )
então também é equivalente a:
NOT (
x = 1
OR
x = NULL
)
e de acordo com as leis de De Morgan é equivalente a:
NOT ( x = 1 ) AND NOT ( x = NULL )
e (se substituirmos
NOT x = y
com x <> y
) também é equivalente a: x <> 1 AND x <> NULL
Observe atentamente a última condição:
WHERE
x <> 1 AND x <> NULL
Sabemos que
x <> NULL
sempre avalia como NULL. Também sabemos da tabela 3VL acima, que tanto true AND NULL
é NULL e false AND NULL
é avaliada como FALSE, portanto, toda a condição sempre é avaliada como FALSE ou NULL, mas nunca é avaliada como TRUE.Portanto, uma consulta com esta condição:
SELECT .....
WHERE x NOT IN ( NULL, whatever)
sempre retorna um conjunto de resultados vazio
E agora sua consulta, que também é curiosa:
SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);
que pode ser reescrita (usando valores constantes) para:
SELECT * FROM t1
WHERE (id, val) NOT IN (
(1, null),
(2, 2 )
)
Esta consulta está usando a chamada expressão de valor de linha
Basicamente uma condição usando o valor de linha expresso assim
(a, b) = (x, y)
é equivalente a este:
a = x AND b = y
então a consulta acima pode ser reescrita nesta:
SELECT * FROM t1
WHERE NOT (
id = 1 AND val = NULL
OR
id = 2 AND val = 2
)
De acordo com as leis de De Morgan, isso é idêntico a:
SELECT * FROM t1
WHERE
NOT ( id = 1 AND val = NULL )
AND
NOT ( id = 2 AND val = 2 )
e ainda para:
SELECT * FROM t1
WHERE
( id <> 1 OR val <> NULL )
AND
( id <> 2 OR val <> 2 )
Desde a primeira parte
( id <> 1 OR val <> NULL )
da condição é avaliada como verdadeira somente no caso em que id <> 1
(veja a tabela 3VL acima), esta condição pode ser simplificada em:SELECT * FROM t1
WHERE
( id <> 1 )
AND
( id <> 2 OR val <> 2 )
e ainda (de acordo com as leis de De Morgan) em:
SELECT * FROM t1
WHERE
id <> 1 AND id <> 2
OR
id <> 1 AND val <> 2
então nem
(1,1)
nem (2,2)
da fonte data1
cumprir estas condições.