On peut conclure des réponses ici qui NOT IN (subquery)ne traitent pas correctement les valeurs nulles et doivent être évitées en faveur de NOT EXISTS. Cependant, une telle conclusion peut être prématurée. Dans le scénario suivant, attribué à Chris Date (Database Programming and Design, Vol 2 No 9, septembre 1989), c'est NOT INqu'il gère correctement les valeurs nulles et renvoie le résultat correct, plutôt que NOT EXISTS.
Considérons un tableau sppour représenter les fournisseurs ( sno) qui sont connus pour fournir des pièces ( pno) en quantité ( qty). Le tableau contient actuellement les valeurs suivantes:
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
Notez que la quantité peut être annulée, c'est-à-dire pour pouvoir enregistrer le fait qu'un fournisseur est connu pour fournir des pièces même s'il n'est pas connu en quelle quantité.
La tâche consiste à trouver les fournisseurs connus qui fournissent le numéro de pièce «P1» mais pas en quantités de 1000.
Les utilisations suivantes permettent NOT INd'identifier correctement le fournisseur «S2» uniquement:
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'
);
Cependant, la requête ci-dessous utilise la même structure générale mais avec NOT EXISTSmais inclut incorrectement le fournisseur «S1» dans le résultat (c'est-à-dire pour lequel la quantité est nulle):
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
);
Ce NOT EXISTSn'est donc pas la balle d'argent qu'elle a pu apparaître!
Bien sûr, la source du problème est la présence de nulls, donc la «vraie» solution est d'éliminer ces nulls.
Ceci peut être réalisé (entre autres conceptions possibles) en utilisant deux tableaux:
sp fournisseurs connus pour fournir des pièces
spq fournisseurs connus pour fournir des pièces en quantités connues
notant qu'il devrait probablement y avoir une contrainte de clé étrangère où les spqréférences sp.
Le résultat peut ensuite être obtenu en utilisant l'opérateur relationnel «moins» (qui est le EXCEPTmot clé dans SQL standard), par exemple
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 INen une série de<> andchangements modifie le comportement sémantique de pas dans cet ensemble à autre chose?