SQL-Abfrage zum Suchen eines Datensatzes mit ID, der sich nicht in einer anderen Tabelle befindet

123

Ich habe zwei Tabellen mit verbindlichem Primärschlüssel in der Datenbank und möchte einen disjunkten Satz zwischen ihnen finden. Beispielsweise,

  • Table1hat Spalten ( ID, Name) und Beispieldaten:(1 ,John), (2, Peter), (3, Mary)
  • Table2hat Spalten ( ID, Address) und Beispieldaten:(1, address2), (2, address2)

So wie erstelle ich eine SQL - Abfrage , damit ich die Zeile mit der ID holt aus , table1dass nicht in ist table2. In diesem Fall (3, Mary)sollte zurückgegeben werden?

Ps. Die ID ist der Primärschlüssel für diese beiden Tabellen.

Danke im Voraus.

Johnklee
quelle
3
Als Tipp für zukünftige Fragen: Definieren Sie immer, welches Datenbanksystem (und welche Version dieser Datenbank) Sie verwenden. SQL ist nur die strukturierte Abfragesprache, die von den meisten Datenbanksystemen verwendet wird - das hilft nicht viel ... Oft haben Datenbanken Erweiterungen und Funktionen, die weit über den ANSI / ISO-SQL-Standard hinausgehen und die Lösung des Problems vereinfachen - aber dafür sind Sie müssen uns sagen, welche Datenbank Sie verwenden
marc_s
5
@marc_s: Was ist, wenn sie nach einer sprachunabhängigen Lösung suchen, weil sie mehrere zugrunde liegende Datenbanksysteme unterstützen müssen oder die Datenbankimplementierung abstrahiert wird?
Dwanderson
Hallo @marc_s, ich verwende in diesem Fall PostgreSQL. Danke für die Erinnerung.
Johnklee

Antworten:

213

Versuche dies

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)
Prinz Jea
quelle
8
@ PrinceJea eigentlich kommt es darauf an. Siehe hier zur Klarstellung
John Woo
Wenn ich 20 Daten habe, funktioniert es, aber wenn ich 20000 Daten habe, funktioniert es nicht, ich bin jetzt verwirrt.
Frank
1
Keine Ahnung warum, aber es funktioniert nicht. Ich habe ungefähr 10000 Zeilen in der Tabelle. In meinem Fall hat die Lösung von @JohnWoo einwandfrei funktioniert.
Munam Yousuf
4
Es wird nicht funktionieren, wenn
G.Busato
2
Ich hatte es , wie dies zu tun: Wählen Sie i aus Tabelle 1 , wo ich nicht IN (i FROM Table2 SELECT , wo ich nicht null ist ) und i nicht null
jaksco
93

Verwenden LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL
John Woo
quelle
Ich denke, dies ist der schnellere Ansatz für eine sehr große Datenbank
Alex Jolig
12

Grundsätzlich gibt es drei Ansätze , dass: not exists, not inund left join / is null.

LINKS VERBINDEN mit IST NULL

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

NICHT IN

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

EXISTIERT NICHT

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

Welches ist besser? Die Antwort auf diese Frage ist möglicherweise besser, wenn sie auf wichtige spezifische RDBMS-Anbieter aufgeteilt wird. Im Allgemeinen sollte die Verwendung vermieden werden, select ... where ... in (select...)wenn die Größe der Anzahl der Datensätze in der Unterabfrage unbekannt ist. Einige Anbieter beschränken möglicherweise die Größe. Oracle hat beispielsweise ein Limit von 1.000 . Am besten probieren Sie alle drei aus und zeigen den Ausführungsplan.

Speziell für PostgreSQL sind Ausführungsplan NOT EXISTSund LEFT JOIN / IS NULLgleich. Ich persönlich bevorzuge die NOT EXISTSOption, weil sie die Absicht besser zeigt. Schließlich ist die Semantik, dass Sie Datensätze in A finden möchten, deren pk in B nicht vorhanden sind .

Alt, aber immer noch Gold, spezifisch für PostgreSQL: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/

L. Holanda
quelle
10

Schnelle Alternative

Ich habe einige Tests (auf Postgres 9.5) mit zwei Tabellen mit jeweils ~ 2 Millionen Zeilen durchgeführt. Diese Abfrage unten hat mindestens 5 * besser abgeschnitten als die anderen vorgeschlagenen Abfragen:

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;
polvoazul
quelle
1
Dies war nicht schneller als die Lösung von @Jhon Woo. Ich verwende Postgres 9.6 und mit Jhons Lösung beträgt die Laufzeit ca. 60 ms. Während ich ziemlich diese Lösung nach 120 Sekunden und kein Ergebnis.
Froy001
5

Unter Berücksichtigung der Punkte, die in @John Woos Kommentar / Link oben gemacht wurden, würde ich normalerweise so damit umgehen:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)
CaseyR
quelle
2
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For count


SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For results
JoshYates1980
quelle