Aus den Antworten hier kann geschlossen werden, dass NOT IN (subquery)
Nullen nicht richtig behandelt werden und zugunsten von vermieden werden sollten NOT EXISTS
. Eine solche Schlussfolgerung kann jedoch verfrüht sein. In dem folgenden Szenario, das Chris Date (Database Programming and Design, Band 2, Nr. 9, September 1989) NOT IN
gutgeschrieben wurde, werden Nullen korrekt behandelt und das richtige Ergebnis zurückgegeben, anstatt NOT EXISTS
.
Betrachten Sie eine Tabelle sp
, um Lieferanten ( sno
) darzustellen , von denen bekannt ist, dass sie Teile ( pno
) in Menge ( qty
) liefern . Die Tabelle enthält derzeit die folgenden Werte:
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
Beachten Sie, dass die Menge nullbar ist, dh um erfassen zu können, dass ein Lieferant bekanntermaßen Teile liefert, auch wenn nicht bekannt ist, in welcher Menge.
Die Aufgabe besteht darin, die Lieferanten zu finden, deren Lieferteilnummer 'P1' bekannt ist, jedoch nicht in Mengen von 1000.
Folgendes wird verwendet NOT IN
, um nur den Lieferanten 'S2' korrekt zu identifizieren:
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'
);
Die folgende Abfrage verwendet jedoch dieselbe allgemeine Struktur, enthält NOT EXISTS
jedoch fälschlicherweise den Lieferanten 'S1' im Ergebnis (dh für den die Menge null ist):
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
);
Also NOT EXISTS
ist nicht die Silberkugel, die es erschienen sein könnte!
Die Ursache des Problems ist natürlich das Vorhandensein von Nullen, daher besteht die "echte" Lösung darin, diese Nullen zu beseitigen.
Dies kann (neben anderen möglichen Designs) anhand von zwei Tabellen erreicht werden:
sp
Lieferanten, von denen bekannt ist, dass sie Teile liefern
spq
Lieferanten, von denen bekannt ist, dass sie Teile in bekannten Mengen liefern
Beachten Sie, dass es wahrscheinlich eine Fremdschlüsseleinschränkung geben sollte, auf die spq
verwiesen wird sp
.
Das Ergebnis kann dann mit dem Vergleichsoperator 'minus' (der das EXCEPT
Schlüsselwort in Standard SQL ist) erhalten werden, z
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 IN
in eine Reihe von<> and
Änderungen das semantische Verhalten von nicht in dieser Menge auf etwas anderes ändert ?