Pode-se concluir a partir de respostas aqui que NOT IN (subquery)não tratam nulos corretamente e devem ser evitadas em favor de NOT EXISTS. No entanto, essa conclusão pode ser prematura. No cenário a seguir, creditado a Chris Date (Database Programming and Design, Vol. 2, n. 9, setembro de 1989), é NOT INque lida com nulos corretamente e retorna o resultado correto, em vez deNOT EXISTS .
Considere uma tabela sppara representar os fornecedores ( sno) que são conhecidos por fornecer peças ( pno) em quantidade ( qty). A tabela atualmente possui os seguintes valores:
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
Observe que a quantidade é anulável, ou seja, para poder registrar o fato de que um fornecedor é conhecido por fornecer peças, mesmo que não seja conhecido em qual quantidade.
A tarefa é encontrar os fornecedores que sabem o número da peça de fornecimento 'P1', mas não em quantidades de 1000.
Os seguintes usos usam NOT INpara identificar corretamente apenas o fornecedor 'S2':
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND 1000 NOT IN (
SELECT spy.qty
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
);
No entanto, a consulta abaixo usa a mesma estrutura geral, mas com, NOT EXISTSmas inclui incorretamente o fornecedor 'S1' no resultado (ou seja, para o qual a quantidade é nula):
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND NOT EXISTS (
SELECT *
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
AND spy.qty = 1000
);
Portanto, NOT EXISTSnão é a bala de prata que pode ter aparecido!
Obviamente, a fonte do problema é a presença de nulos; portanto, a solução 'real' é eliminar esses nulos.
Isso pode ser alcançado (entre outros projetos possíveis) usando duas tabelas:
sp fornecedores conhecidos por fornecer peças
spq fornecedores conhecidos por fornecer peças em quantidades conhecidas
observando que provavelmente deve haver uma restrição de chave estrangeira em que as spqreferênciassp .
O resultado pode ser obtido usando o operador relacional 'menos' (sendo a EXCEPTpalavra - chave no SQL padrão), por exemplo
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1' ),
( 'S2', 'P1' ),
( 'S3', 'P1' ) )
AS T ( sno, pno )
),
spq AS
( SELECT *
FROM ( VALUES ( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT sno
FROM spq
WHERE pno = 'P1'
EXCEPT
SELECT sno
FROM spq
WHERE pno = 'P1'
AND qty = 1000;
NOT INpara uma série de<> andmudanças altera o comportamento semântico de não neste conjunto para outra coisa?