MySQL-Abfrage "NICHT IN"


181

Ich wollte eine einfache Abfrage ausführen, um alle Zeilen aufzurufen, in Table1denen ein Hauptspaltenwert in einer Spalte in einer anderen Tabelle ( Table2) nicht vorhanden ist .

Ich habe versucht:

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal

Dies löst stattdessen einen Syntaxfehler aus. Die Google-Suche führte mich zu Foren, in denen Leute sagten, dass MySQL nicht unterstützt NOT INund etwas extrem Komplexes verwendet werden muss. Ist das wahr? Oder mache ich einen schrecklichen Fehler?


1
Und was ist, wenn ich ähnliche Daten aus drei Tabellen möchte? Ich meine, eine Tabelle1 hat 2000 Einträge, die anderen beiden Tabellen 2 und 3 haben jeweils 500 Einträge, alle haben das gemeinsame Feld 'Name'. Wie können wir alle Details aus Tabelle 1 erhalten, die in Tabelle 2 und 3 nicht vorhanden sind, basierend auf 'Name'. Können wir NOT IN zweimal verwenden, wenn ja wie ..?

Antworten:


310

Um IN verwenden zu können, müssen Sie einen Satz haben. Verwenden Sie stattdessen diese Syntax:

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)

85
Vorsicht wann table2.principalkann sein NULL. In diesem Fall NOT INwird immer zurückgegeben, FALSEweil NOT INbehandelt wird als <> ALL, was alle Zeilen aus der Unterabfrage wie vergleicht Table1.principal <> table2.principal, was beim Vergleich mit fehlschlägt NULL: Table1.principal <> NULLführt nicht zu TRUE. So beheben Sie : NOT IN (SELECT principal FROM table2 WHERE principal IS NOT NULL).
Basti

4
Danke für den Kommentar @Basti! Ich habe viel Zeit damit verbracht zu verstehen, warum die Abfrage nicht wie erwartet funktioniert hat.
Gvas

3
Vergessen Sie nicht, die Verwendung von 'SELECT *' in der Liste 'NOT IN' zu vermeiden. Sie müssen eine bestimmte Spalte auswählen. Andernfalls wird folgende Fehlermeldung angezeigt
Lorien Brune

165

Die Unterabfrageoption wurde bereits beantwortet. Beachten Sie jedoch, dass a in vielen Fällen LEFT JOINeine schnellere Möglichkeit ist, dies zu tun:

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL

Wenn Sie mehrere Tabellen überprüfen möchten, um sicherzustellen, dass sie in keiner der Tabellen vorhanden sind (wie im Kommentar von SRKR), können Sie Folgendes verwenden:

SELECT table1.*
FROM table1
LEFT JOIN table2 ON table2.name=table1.name
LEFT JOIN table3 ON table3.name=table1.name
WHERE table2.name IS NULL AND table3.name IS NULL

2
Hatte in meinen eigenen Tests die gleiche Leistung für beide NOT IN& LEFT JOIN. +1 beide
BufferStack

Sobald die Abfrage einmal ausgeführt wurde, sollten Sie die gleichen Ergebnisse erhalten, egal was aufgrund des internen DB-Caching
passiert

Für mich war die Leistung viel besser. Ich ging durch verschiedene Tische, während sie Fremdschlüssel gesetzt hatten.
Keenora Fluffball

36

NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL in MySQL

MySQL sowie alle anderen Systeme außer SQL Server können optimieren LEFT JOIN/ zurückgebenIS NULL , FALSEsobald der übereinstimmende Wert gefunden wurde, und es ist das einzige System, das dieses Verhalten dokumentiert. […] Da MySQL keine Algorithmen verwenden HASHund MERGEverbinden kann, ist das einzige, was ANTI JOINes kann, dasNESTED LOOPS ANTI JOIN

[…]

Im Wesentlichen ist [ NOT IN] genau derselbe Plan, den LEFT JOIN/ IS NULLverwendet, obwohl diese Pläne von den verschiedenen Codezweigen ausgeführt werden und in den Ergebnissen von unterschiedlich aussehen EXPLAIN. Die Algorithmen sind tatsächlich gleich und die Abfragen werden zur gleichen Zeit abgeschlossen.

[…]

Es ist schwierig, den genauen Grund für [Leistungsabfall bei Verwendung NOT EXISTS] zu ermitteln , da dieser Abfall linear ist und nicht von der Datenverteilung, der Anzahl der Werte in beiden Tabellen usw. abhängt, solange beide Felder indiziert sind. Da es in MySQL drei Codeteile gibt, die im Wesentlichen einen Job ausführen, ist es möglich, dass der Code, für den er verantwortlich EXISTSist, eine zusätzliche Überprüfung durchführt, die zusätzliche Zeit in Anspruch nimmt.

[…]

MySQL kann alle drei Methoden für eine Art von optimieren NESTED LOOPS ANTI JOIN. […] Diese drei Methoden generieren jedoch drei verschiedene Pläne, die von drei verschiedenen Codeteilen ausgeführt werden. Der Code, der das EXISTSPrädikat ausführt, ist etwa 30% weniger effizient […]

Aus diesem Grund können Sie in MySQL am besten nach fehlenden Werten suchen, indem Sie ein LEFT JOIN/ IS NULLoder NOT INanstelle von verwenden NOT EXISTS.

(Hervorhebungen hinzugefügt)


7

Leider scheint es ein Problem mit der MySQL-Verwendung der "NOT IN" -Klausel zu sein. Der folgende Screenshot zeigt die Unterabfrageoption, die falsche Ergebnisse zurückgibt:

mysql> show variables like '%version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 1.1.8                        |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.5.21                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
7 rows in set (0.07 sec)

mysql> select count(*) from TABLE_A where TABLE_A.Pkey not in (select distinct TABLE_B.Fkey from TABLE_B );
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from TABLE_A left join TABLE_B on TABLE_A.Pkey = TABLE_B.Fkey where TABLE_B.Pkey is null;
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from TABLE_A where NOT EXISTS (select * FROM TABLE_B WHERE TABLE_B.Fkey = TABLE_A.Pkey );
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> 

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.