Kategorien
Computer MySQL Tutorials

Die Angst des Programmierers vor dem SQL-Join

Ein Artikel von Jeff Atwood in seinem Blog „Coding Horror“ sowie zwei passgenau zum gleichen Zeitpunkt sich ereignende programmiertechnische Episoden reizen mich, mal eine Lanze für Joins in SQL-Statements zu brechen. Joins sind eine schöne Sache und eigentlich nicht sehr schwierig. Aktuelle RDBMS kommen prima mit Joins aus, also gibt es Gründe, auf Joins zu verzichten?

Beginnen wir mal mit zwei Tabellen, um die Vergleiche zu beginnen. Als Thema bewege ich mich mal auf glühende Kohlen, also ab in die Politik!

[sourcecode language=“sql“]
CREATE TABLE `spd_politiker` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(40) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB; [/sourcecode]

[sourcecode language=“sql“]
CREATE TABLE `minister` (
`ID` int(11) NOT NULL,
`Name` varchar(40) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB; [/sourcecode]

….und zum Spielen nehmen wir auch noch ein paar Daten aus dem harten Berliner Politikalltag…

Tabelle Minister:                  Tabelle SPD-Politiker
ID Name                            ID Name
-- ----                            -- ----
 1 Frank-Walter Steinmeier          1 Franz Müntefering
 2 Wolfgang Schäuble                2 Frank-Walter Steinmeier
 3 Brigitte Zypries                 3 Brigitte Zypries
 4 Peer Steinbrück                  4 Peer Steinbrück
 5 Michael Glos                     5 Ulla Schmidt
 6 Franz Müntefering                6 Wolfgang Tiefensee
 7 Horst Seehofer                   7 Sigmar Gabriel
 8 Franz Josef Jung                 8 Willy Brandt
 9 Ursula von der Leyen             9 Helmut Schmidt
10 Ulla Schmidt                    10 Gerhard Schröder
11 Wolfgang Tiefensee              11 Kurt Beck
12 Sigmar Gabriel                  12 Johannes Rau
13 Annette Schavan

Ran an die SQL-Joins…

1. INNER JOIN

Inner JoinEin inner join liefert im Prinzip die Schnittmenge aus beiden Grundmengen. Für das konstruierte Beispiel aus der Politik würden also alle Minister ausgegeben werden, welche gleichzeitig SPD-Politiker sind bzw. waren.

[sourcecode language=“sql“]
select * from minister
inner join spd_politiker on minister.Name = spd_politiker.Name;
[/sourcecode]

ID Name ID Name
1 Frank-Walter Steinmeier 2 Frank-Walter Steinmeier
3 Brigitte Zypries 3 Brigitte Zypries
4 Peer Steinbrück 4 Peer Steinbrück
6 Franz Müntefering 1 Franz Müntefering
10 Ulla Schmidt 5 Ulla Schmidt
11 Wolfgang Tiefensee 6 Wolfgang Tiefensee
12 Sigmar Gabriel 7 Sigmar Gabriel

In diesem Fall kann man das gewünschte Ergebnis noch etwas einfacher erhalten, jedoch behandelt dieser Artikel das Verhalten von Joins…!

2. LEFT (OUTER) JOIN

Left JoinEin left outer join liefert als Ergebnis alle Datensätze der ersten Tabelle sowie alle passenden Datensätze von Tabelle 2. Hier werden somit alle Minister ausgegeben, als Ergänzung erscheinen die Daten aus der SPD-Politiker-Tabelle, falls ein Minister dort enthalten sein sollte.

[sourcecode language=“sql“]
select * from minister
left outer join spd_politiker
on minister.Name = spd_politiker.Name;
[/sourcecode]

ID Name ID Name
1 Frank-Walter Steinmeier 2 Frank-Walter Steinmeier
2 Wolfgang Schäuble (NULL) (NULL)
3 Brigitte Zypries 3 Brigitte Zypries
4 Peer Steinbrück 4 Peer Steinbrück
5 Michael Glos (NULL) (NULL)
6 Franz Müntefering 1 Franz Müntefering
7 Horst Seehofer (NULL) (NULL)
8 Franz Josef Jung (NULL) (NULL)
9 Ursula von der Leyen (NULL) (NULL)
10 Ulla Schmidt 5 Ulla Schmidt
11 Wolfgang Tiefensee 6 Wolfgang Tiefensee
12 Sigmar Gabriel 7 Sigmar Gabriel
13 Annette Schavan (NULL) (NULL)

Häufig verwende ich diese left outer joins, um Datensätze zu finden, welche nicht in der anderen Tabelle vorhanden sind. Hierfür kann man die SQL-Abfrage leicht modifizieren – das Ergebnis ist in diesem Falle alle Nicht-SPD-Minister:

[sourcecode language=“sql“]
select * from minister
left outer join spd_politiker
on minister.Name = spd_politiker.Name
where spd_politiker.ID IS NULL;
[/sourcecode]

3. RIGHT (OUTER) JOIN

Ein right outer join funktioniert eigentlich genauso wie ein left outer join liefert als Ergebnis alle Datensätze der zweiten Tabelle sowie alle passenden Datensätze von Tabelle 1. Hier werden somit alle SPD-Politiker ausgegeben, als Ergänzung erscheinen die Daten aus der Minister-Tabelle, falls der Politiker dort auch ein Amt bekleidet.

[sourcecode language=“sql“]
select * from minister
right outer join spd_politiker
on minister.Name = spd_politiker.Name;
[/sourcecode]

ID Name ID Name
6 Franz Müntefering 1 Franz Müntefering
1 Frank-Walter Steinmeier 2 Frank-Walter Steinmeier
3 Brigitte Zypries 3 Brigitte Zypries
4 Peer Steinbrück 4 Peer Steinbrück
10 Ulla Schmidt 5 Ulla Schmidt
11 Wolfgang Tiefensee 6 Wolfgang Tiefensee
12 Sigmar Gabriel 7 Sigmar Gabriel
(NULL) (NULL) 8 Willy Brandt
(NULL) (NULL) 9 Helmut Schmidt
(NULL) (NULL) 10 Gerhard Schröder
(NULL) (NULL) 11 Kurt Beck
(NULL) (NULL) 12 Johannes Rau

Auch mit dem right outer joins kann man wunderbar die IS NULL-Eigenschaft verwenden, um Datensätze zu finden, welche nicht in der anderen Tabelle vorhanden sind.

4. FULL OUTER JOIN
Full Outer JoinEin full outer join gibt eigentlich alle Datensätze von Tabelle A und Tabelle B aus, wobei die Schnittmenge zusammengefasst wird. Ein paar RDBMS, wie z.B. auch MySQL, haben keine direkte Unterstützung des full outer join, jedoch kann man ohne viel Umstand SQL-Konstrukte basteln, die dies imitieren – schließlich ist das ja nichts anderes wie eine Zusammenfassung des left outer join und des right outer join.

Hier ein Beispiel eines Workarounds für MySQL mit Verwendung von union all:
[sourcecode language=“sql“]
select * from minister
left outer join spd_politiker
on minister.Name = spd_politiker.Name
union all
select * from minister
right outer join spd_politiker
on minister.Name = spd_politiker.Name
where minister.Name is null;
[/sourcecode]

ID Name ID Name
1 Frank-Walter Steinmeier 2 Frank-Walter Steinmeier
2 Wolfgang Schäuble (NULL) (NULL)
3 Brigitte Zypries 3 Brigitte Zypries
4 Peer Steinbrück 4 Peer Steinbrück
5 Michael Glos (NULL) (NULL)
6 Franz Müntefering 1 Franz Müntefering
7 Horst Seehofer (NULL) (NULL)
8 Franz Josef Jung (NULL) (NULL)
9 Ursula von der Leyen (NULL) (NULL)
10 Ulla Schmidt 5 Ulla Schmidt
11 Wolfgang Tiefensee 6 Wolfgang Tiefensee
12 Sigmar Gabriel 7 Sigmar Gabriel
13 Annette Schavan (NULL) (NULL)
(NULL) (NULL) 8 Willy Brandt
(NULL) (NULL) 9 Helmut Schmidt
(NULL) (NULL) 10 Gerhard Schröder
(NULL) (NULL) 11 Kurt Beck
(NULL) (NULL) 12 Johannes Rau

Mehr Methoden, um einen full outer join mit MySQL nachzubauen, habe ich hier gefunden.

Anmerkung:
Wie der Kommentator Steffen korrekterweise moniert, ist ein JOIN tatsächlich keine Schnittmenge, sondern vielmehr ein kartesisches Produkt in Verbindung mit einer Selektion. Datenbanktheoretiker mögen mich strafen, aber ich bleibe dennoch bei meiner starken Vereinfachung in diesem Artikel!

Von Björn

Tja, ich bin Schöpfer und Admin von dieser Seite!

27 Antworten auf „Die Angst des Programmierers vor dem SQL-Join“

Hallo Steffen,

das ist natürlich fachlich vollkommen korrekt, und um den querulatorischen Frieden zu wahren ist nun eine kleine Fußnote in dem Artikel.

Beste Grüße,
Björn

Hallo Björn,
die Relationale Algebra definiert das o.g. sauber und hinreichend verständlich (kartesisches Produkt&Selektion). Es gibt Aussagen, die man „unter Brüdern“ gelten lassen könnte: um im Bsp. zu bleiben „Politiker sind **********“. Der Aussage „Inner Joins = Schnittmenge“ kann man auch „unter Brüdern“ nicht zustimmen.

Querulatorischen aber lieben Gruß
Steffen

Hallo Steffen,

klar kann – je nach Anwendungsfall der INNER JOIN mehr Datensätze produzieren als in den Quelltabellen. Ziel der Visualisierung ist jedoch auf Basis von möglichst einfach verständlichen Daten es fürs Auge zu transportieren.

Gegenfrage:
Wie würdest Du es möglichst einfach beschreiben?

Viele Grüße,
Björn

Hallo Björn,
mir geht es nicht um didaktische Aspekte, sondern um die Tatsache, dass eine via Inner Join generierte Tabelle bspw. mehr Datensätze enthalten kann, als die abgefragten Tabellen zusammen. Mich wundert, dass dieser Umstand hier niemanden und insbesondere Dich nicht stört?!
Also schon quantitativ ist die Aussage „Inner Join = Schnittmenge“ einfach nur FALSCH! Da hilft es gar nicht, dass es doch so schön anschaulich ist…
Auch die Aussage „Politiker sind häßliche Frauen mit schrecklichen Dekolletes“ mag leicht verständlich sein und sogar auf unsern süßen Kanzlerengel zutreffen, aber i.A. bleibt es eben falsch!

Liebe Grüße
Steffen

Ein Mengendiagramm ist sicherlich nicht wissenschaftlich die beste Visualisierung eines Joins, aber es hat den Vorteil, dass es fast jeder kennt. Ich halte es auch nach mehreren Jahren für eine gute Näherung.

Hallo,
die Visualisierung mittels Venn-Diagrammen ist hier, wie auch an vielen anderen Stellen im I-Net falsch. Bspw. kann die Schnittmenge zweier Tabellen i.A. nicht über ein
einfaches Inner Join gebildet werden.
Gruß
Steffen

Sehr gut veranschaulicht und sehr hilfreich. Vielen Dank!
Daran könnte sich der Eine oder Andere Lehrkörper ein Beispiel nehmen 🙂

Wirklich klasse!!! Einfach und effektiv erklärt ! Solche Beiträge erleichtern das Leben 🙂

In meinen Beispielen geht es eher darum, die Relationen darzustellen, welche sich aus den diversen JOIN-Varianten ergeben. Durch die eindeutigen Namen gibt es nur 1:1-Relation. Das von Ihnen beschriebene Szenario kommt vor, wenn man mit 1:n-Relationen arbeitet. Hier hilft DISTINCT (falls man es denn möchte), denn diese Option legt fest, dass doppelte Datensätze aus der Ergebnismenge entfernt werden.

Hallo, ich dachte auch, dass ich das Wesentliche Begriffen habe, bis ich auf folgendes Problem stieß: wenn in der Tabelle B ein Eintrag doppelt vorkommt, wird er beim dieser passgleiche Eintrag doppelt angezeigt. Vermutlich muss man dann noch den Select mit einem Distinct ausführen um das Problem zu beheben. Richtig?

Danke! Eigentlich wollte ich auch den Artikel um den NATURAL JOIN erweitern, jedoch fand ich bislang kein passendes Beispiel. Vielmehr wäre es sicher irgendwann einmal sinnvoll, den Artikel auf die aktuellen politischen Gegebenheiten zu aktualisieren – da warte ich aber erstmal die Wahlen im Herbst ab!

Ich kann mich meinen Vorrednern nur anschließen. Sehr gute Seite. Fast schon vorbildlich 😉

Eventuell könnte man die Übersicht noch um die Natural joins erweitern

Die Abfrage aller Nicht-SPD-Minister würde ich ja eher so machen (hat dann aber nichts mit Joins zu tun):

select * from minister
where id not in
(
select id
from spd_politiker
)

Eine sehr hilfreiche Seite, weil es wirklich einfach und verständlich erklärt ist!

Sehr, sehr hilfreich! Habs nun endlich mal verstanden, und hoffe es hilft mir auch über die mündliche Informatik-Abiturprüfung hinaus 😉 Viele Dank!

Prima erklärt mit einem lebensnahen und einfach nachvollziehbaren Beispiel. Klasse!

Sehr aufschlussreich geschrieben.
Jetzt kann meine Klausur kommen 😉
Großes Lob

Gern geschehen! 🙂 Vielleicht sollte ich irgendwann einmal die benannten Politiker in diesem Tutorial aktualisieren…

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.