Der EXCEPT
Operator wurde in SQL Server 2005 eingeführt, aber was ist der Unterschied zwischen NOT IN
und EXCEPT
?
Tut es das selbe? Ich hätte gerne eine einfache Erklärung mit einem Beispiel.
Der EXCEPT
Operator wurde in SQL Server 2005 eingeführt, aber was ist der Unterschied zwischen NOT IN
und EXCEPT
?
Tut es das selbe? Ich hätte gerne eine einfache Erklärung mit einem Beispiel.
Antworten:
Es gibt zwei Hauptunterschiede zwischen EXCEPT
und NOT IN
.
EXCEPT
filtert die DISTINCT
Werte aus der linken Tabelle, die nicht in der rechten Tabelle erscheinen. Es ist im Grunde dasselbe wie NOT EXISTS
mit einer DISTINCT
Klausel.
Es wird auch erwartet, dass die beiden Tabellen (oder eine Teilmenge von Spalten aus den Tabellen) links und rechts der Abfrage dieselbe Anzahl von Spalten aufweisen
Zum Beispiel können Sie nicht tun:
SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB
Dies würde zu folgendem Fehler führen:
Alle Abfragen, die mit einem UNION-, INTERSECT- oder EXCEPT-Operator kombiniert werden, müssen die gleiche Anzahl von Ausdrücken in ihren Ziellisten enthalten.
NOT IN
filtert nicht nach DISTINCT
Werten und gibt alle Werte aus der linken Tabelle zurück, die nicht in der rechten Tabelle enthalten sind.
NOT IN
erfordert, dass Sie eine einzelne Spalte aus einer Tabelle mit einer einzelnen Spalte aus einer anderen Tabelle oder Unterabfrage vergleichen.
Wenn Ihre Unterabfrage beispielsweise mehrere Spalten zurückgeben soll:
SELECT * FROM TableA AS nc
WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec)
Sie würden den folgenden Fehler erhalten:
In der Auswahlliste kann nur ein Ausdruck angegeben werden, wenn die Unterabfrage nicht mit EXISTS eingeführt wird.
Wenn die rechte Tabelle jedoch ein NULL
in den Werten enthält, nach denen gefiltert wird NOT IN
, wird eine leere Ergebnismenge zurückgegeben, die möglicherweise zu unerwarteten Ergebnissen führt.
CREATE TABLE #NewCustomers (ID INT);
CREATE TABLE #ExistingCustomers (ID INT);
INSERT INTO #NewCustomers
( ID )
VALUES
(8), (9), (10), (1), (3), (8);
INSERT INTO #ExistingCustomers
( ID )
VALUES
( 1) , (2), (3), (4), (5);
-- EXCEPT filters for DISTINCT values
SELECT * FROM #NewCustomers AS nc
EXCEPT
SELECT * FROM #ExistingCustomers AS ec
-- NOT IN returns all values without filtering
SELECT * FROM #NewCustomers AS nc
WHERE ID NOT IN (SELECT ID FROM #ExistingCustomers AS ec)
Gibt aus den beiden obigen Abfragen EXCEPT
3 Zeilen zurück #NewCustomers
, wobei die übereinstimmenden 1 und 3 #ExistingCustomers
sowie das Duplikat 8 herausgefiltert werden.
NOT IN
führt diese eindeutige Filterung nicht durch und gibt 4 Zeilen #NewCustomers
mit dem Duplikat 8 zurück.
Wenn wir jetzt a NULL
zur #ExistingCustomers
Tabelle hinzufügen , sehen wir die gleichen Ergebnisse, die von zurückgegeben wurden EXCEPT
, es NOT IN
wird jedoch eine leere Ergebnismenge zurückgegeben.
INSERT INTO #ExistingCustomers
( ID )
VALUES
( NULL );
-- With NULL values in the right-hand table, EXCEPT still returns the same results as above
SELECT * FROM #NewCustomers AS nc
EXCEPT
SELECT * FROM #ExistingCustomers AS ec
-- NOT IN now returns no results
SELECT * FROM #NewCustomers AS nc
WHERE ID NOT IN (SELECT ID FROM #ExistingCustomers AS ec)
DROP TABLE #NewCustomers;
DROP TABLE #ExistingCustomers;
Stattdessen NOT IN
solltest du dir das wirklich ansehen NOT EXISTS
und es gibt einen guten Vergleich zwischen den beiden auf Gail Shaws Blog .
Eine Ergänzung zu Mark Sinkinsons ausgezeichnetem Kommentar:
NOT IN erfordert, dass Sie eine einzelne Spalte aus einer Tabelle mit einer einzelnen Spalte aus einer anderen Tabelle oder Unterabfrage vergleichen.
Sie können tatsächlich NOT IN
mit mehr als einer Spalte arbeiten.
Dies ist zB eine vollkommen legale * SQL-Abfrage:
SELECT E.first_name, E.last_name
FROM employees E
WHERE (E.first_name, E.last_name) NOT IN
(SELECT M.first_name, M.last_name FROM managers M)
Welches zurückkehren wird first_name
und last_name
ausgerechnet Leute, die Angestellte sind, aber nicht auch Manager.
*: aber die Konstruktion ist noch nicht in SQL Server implementiert.
Das oben stehende NOT IN schlägt fehl, da eine Korrelation zwischen den Prädikaten in der Hauptabfrage und der Unterabfrage bestehen muss. Wenn Sie es weglassen, erhalten Sie eine UNKORRELIERTE Unterabfrage.
SELECT * FROM TableA AS nc WHERE ID NICHT IN (SELECT ID, Name FROM TableB AS ec wobei nc.ID = ec.ID)
EXCEPT ist besser und behandelt alle Nullzeilen, ohne IS NULL / IS NOT NULL-Prädikate zu verwenden.