Wie wähle ich alle Datensätze aus einer Tabelle aus, die in einer anderen Tabelle nicht vorhanden sind?


469

Tabelle1 (ID, Name)
Tabelle2 (ID, Name)

Abfrage:

SELECT name   
FROM table2  
-- that are not in table1 already

Antworten:


843
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

F : Was passiert hier?

A : Konzeptionell wählen wir alle Zeilen aus table1und versuchen für jede Zeile eine Zeile table2mit demselben Wert für die nameSpalte zu finden. Wenn es keine solche Zeile gibt, lassen wir einfach den table2Teil unseres Ergebnisses für diese Zeile leer. Dann beschränken wir unsere Auswahl, indem wir nur die Zeilen im Ergebnis auswählen, in denen die übereinstimmende Zeile nicht vorhanden ist. Schließlich ignorieren wir alle Felder aus unserem Ergebnis mit Ausnahme der nameSpalte (von der wir sicher sind, dass sie existiert table1).

Obwohl dies möglicherweise nicht in allen Fällen die leistungsfähigste Methode ist, sollte es in praktisch jeder Datenbank-Engine funktionieren, die jemals versucht, ANSI 92 SQL zu implementieren


16
@ Z-Boss: Es ist auch die am wenigsten leistungsfähige auf SQL Server: explainextended.com/2009/09/15/…
OMG Ponies

7
@BunkerBoy: Ein linker Join ermöglicht, dass Zeilen auf der rechten Seite nicht existieren, ohne dass dies die Aufnahme von Zeilen auf der linken Seite beeinflusst. Für eine innere Verknüpfung müssen Zeilen links und rechts vorhanden sein. Was ich hier mache, ist eine Logik anzuwenden, um im Grunde die umgekehrte Auswahl eines inneren Joins zu erhalten.
Kris

2
omg das half sehr leicht zu visualisieren, andere hatten es auf 5 verschiedene Arten ausgedrückt, aber das half. Einfach: Zuerst erhalten Sie einen Link-Join, alles in A und alles in B, was mit A übereinstimmt. Aber wie in Links-Join-Feldern, die nicht beitreten, sind sie einfach null. Dann sagst du, ok ich will nur das sind null. Auf diese Weise haben Sie jetzt alle Zeilen in A, die keine Übereinstimmung hatten In B
Muhammad Umer

7
Es sollte beachtet werden, dass diese Lösung (akzeptiert und abgestimmt) die einzige ist, die meiner Meinung nach für ein Szenario bearbeitet werden könnte, in dem mehr als ein Feld ins Spiel kommt. Insbesondere gebe ich Feld, Feld 2, Feld 3 aus Tabelle 1 zurück, wobei die Kombination aus Feld und Feld 2 nicht in der zweiten Tabelle enthalten ist. Abgesehen von der Änderung des Joins in dieser Antwort sehe ich keine Möglichkeit, dies mit einigen der anderen "effizienteren Antworten" zu tun, für die unten argumentiert wird
TMWP

1
Stellen Sie einfach sicher, dass Sie "WHERE t2.name IS NULL" und nicht "AND t2.name IS NULL" verwenden, da "und" keine korrekten Ergebnisse liefern. Ich verstehe nicht wirklich warum, aber es ist eine Tatsache, ich habe es getestet.
user890332

236

Sie können entweder tun

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

oder

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

In dieser Frage finden Sie drei Techniken, um dies zu erreichen


38
Dies ist bei großen Datenmengen unglaublich langsam.
Glühbirne1

Ja, in der Tat ist es sehr langsam
sirus

Sollte es nicht "from table1" in der Unterabfrage der nicht vorhandenen Abfrage sein.
Hound

Sehr verwirrt darüber, wie das so viele positive Stimmen bekommen hat. Es fällt mir sehr schwer, mir einen Grund vorzustellen, dies jemals zu verwenden, wenn es einen Ansatz für dieses Problem gibt, der mit ungefähr der gleichen Anzahl von Tastenanschlägen unglaublich schneller ist.
Searchengine27

Dieser hat für mich gearbeitet. Danke
Thameem

81

Ich habe nicht genug Wiederholungspunkte, um die zweite Antwort abzustimmen. Aber ich muss den Kommentaren zur Top-Antwort nicht zustimmen. Die zweite Antwort:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

Ist in der Praxis weitaus effizienter. Ich weiß nicht warum, aber ich arbeite mit mehr als 800.000 Datensätzen und der Unterschied ist enorm, mit dem Vorteil, den die zweite Antwort oben hat. Nur meine $ 0,02


30
In der NOT IN-Abfrage wird die Unterabfrage nur einmal ausgeführt, in der EXISTS-Abfrage wird die Unterabfrage für jede Zeile ausgeführt
Carrick

1
du bist großartig :) auf diese Weise konvertiere ich meine 25-Sekunden-Abfrage mit Left Join in nur 0,1 Sekunden
Bassem Shahin

3
Die Antworten sind nicht in einer bestimmten Reihenfolge, daher bedeutet die zweite Antwort nicht, was Sie dachten, dass es bedeutet.

38

Dies ist eine reine Mengenlehre, die Sie mit der minusOperation erreichen können.

select id, name from table1
minus
select id, name from table2

Denken Sie, dass dies viel effizienter ist als Left Join?
Uhs

Es sollte sein. Der Minus-Befehl ist genau für diese Situation ausgelegt. Die einzige Möglichkeit, einen bestimmten Datensatz zu beurteilen, besteht natürlich darin, ihn in beide Richtungen auszuprobieren und festzustellen, welcher Datensatz schneller ausgeführt wird.
Winter

9
In T-SQL lautet der Set-Operator "Ausnahme". Dies ist sehr praktisch für mich und hat keine Verlangsamung verursacht.

2
In SQLite ist der Operator "Minus" auch "Ausnahme".
Lebensfreude

MySQL unterstützt den MINUS-Operator nicht.
Muhammad Azeem


16

Achten Sie auf Fallstricke. Wenn das Feld Namein Table1Nullen enthält, werden Sie überrascht sein. Besser ist:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)

1
COALESCE> ISNULL (ISNULL ist eine nutzlose T-SQL-Ergänzung zu der Sprache, die nichts Neues oder Besseres als COALESCE macht)
Kris

14

Folgendes hat für mich am besten funktioniert.

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

Dies war mehr als doppelt so schnell wie jede andere Methode, die ich ausprobiert habe.


Danke, das funktioniert auch gut mit großen Datenmengen! Aber ich wundere mich nur über den Begriff "Außer".
PatsonLeaner


7

Das funktioniert scharf für mich

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL

1

Siehe Abfrage:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

Konzeptionell wäre: Abrufen der übereinstimmenden Datensätze in der Unterabfrage und anschließendes Abrufen der Datensätze, die sich nicht in der Unterabfrage befinden.


0

Ich werde die richtige Antwort erneut posten (da ich noch nicht cool genug bin, um sie zu kommentieren) ... falls jemand anderes der Meinung ist, dass es einer besseren Erklärung bedarf.

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

Und ich habe gesehen, dass Syntax in FROM Kommas zwischen Tabellennamen in mySQL benötigt, aber in sqlLite schien es den Platz zu bevorzugen.

Wenn Sie falsche Variablennamen verwenden, bleiben unter dem Strich Fragen zurück. Meine Variablen sollten sinnvoller sein. Und jemand sollte erklären, warum wir ein Komma oder kein Komma brauchen.


0

Wenn Sie einen bestimmten Benutzer auswählen möchten

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

Das tent_npkist ein Primärschlüssel eines Benutzers

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.