Ausschluss von Datensätzen mittels (LEFT) JOIN

Ausschluss mittels (INNER) JOIN

Nehmen wir an, wir haben 2 Tabellen und möchten nun nur die Datensätze erhalten, die in beiden Tabellen enthalten sind.
Man kann zwar auch die Funktion
select foo
from bar
where foo in (select foo from baz)

nutzen, bei großen Tabellen leidet die Performance aber extrem. Wesentlich performanter ist die Nutzung von JOINs, also
select bar.foo
from bar
join baz on baz.foo=bar.foo
.
Hierbei gehe ich jetzt davon aus, dass es die Werte von foo in der Tabelle baz immer eindeutig sind, es also keine Dubletten gibt. Sollte dem nicht so sein und man auch keine Dubletten habe möchte, muss man das etwas geschickter formulieren. Hierfür wähle ich jetzt ein anschaulicheres Beispiel. Ich habe eine Tabelle mit aktiven Konten und eine mit Umsätzen. In der Umsatz-Tabelle gibt es auch Konten, die mittlerweile aufgelöst sind. Ich möchte alle Konten erhalten, die auch Umsätze haben:

Konten
Kontonummer Kundennummer
18 1
26 2
42 4
Umsatz
Kontonummer Tag Betrag
18 2014-08-01 1000
18 2014-08-02 -1000
34 2014-08-01 -8000
42 2014-07-01 500

Wenn ich nun wie oben beschrieben
select konten.kontonummer
from konten
join umsatz on konten.kontonummer=umsatz.kontonummer

abfeuere, erhalte ich folgendes Ergebnis:

18
18
42

Es sind also Dubletten enthalten. Da wir diese bermeiden möchten, verknüpfen wir stattdessen nicht die komplette Tabelle Umsatz, sondern einen Sub-Select:
select konten.kontonummer
from konten
join (select distinct kontonummer from umsatz) as umsatz_eindeutig on konten.kontonummer=umsatz_eindeutig.kontonummer

Nun erhalten wir das gewünschte Ergebnis:

18
42

Das DISTINCT könnte man in diesem einfachen Beispiel natürlich auch direkt hinter das erste SELECT stellen, aber es gibt ja auch Fälle, wo es in der ersten Tabelle Dubletten gibt, die man erhalten möchte.

Ausschluss mittels LEFT JOIN

Nun nehmen wir an, wir möchten aus obigem Beispiel die umsatzlosen Konten heraussuchen. Man könnten hier wiederum select kontonummer from konten where kontonummer not in (select kontonummer from umsatz) nutzen, aber hier leidet die Performance geauso wie im obigen Beispiel. Einen INNER JOIN können wir nicht nutzen, wir wollen ja genau die anderen Konten. Zum Glück gibt es aber ja noch den LEFT JOIN:

select konten.kontonummer, umsatz.konten
from konten
left join umsatz on konten.kontonummer=umsatz.kontonummer

liefert folgendes Ergebnis:

18 18
18 18
26 NULL
42 42

Uns interessiert hier der Datensatz für das Konto 26 – dieser hat in der 2. Spalte den Wert NULL, so dass wir diesen über eine WHERE-Klausel identifizieren können:

select konten.kontonummer, umsatz.konten
from konten left join umsatz on konten.kontonummer=umsatz.kontonummer
where umsatz.kontonummer is NULL

liefert das gewünschte Ergebnis:

26 NULL

Bei größeren Abfragen zeigen sich die Performancegewinne deutlich. Wir reden nicht von ein paar Sekunden – ich hatte schon SELECTs, die nach einem Umbau von „NOT IN“ zu „LEFT JOIN“ auf einmal keine 2 Sttunden, sondern 30 Sekunden benötigt haben!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.