|
20 Okt |
Die Angst des Programmierers vor dem SQL-Join Computer, MySQL, Tutorials
|
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!
CREATE TABLE `spd_politiker` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `Name` varchar(40) DEFAULT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB;
CREATE TABLE `minister` ( `ID` int(11) NOT NULL, `Name` varchar(40) DEFAULT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB;
….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
Ein 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.
select * from minister inner join spd_politiker on minister.Name = spd_politiker.Name;
| 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
Ein 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.
select * from minister left outer join spd_politiker on minister.Name = spd_politiker.Name;
| 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:
select * from minister left outer join spd_politiker on minister.Name = spd_politiker.Name where spd_politiker.ID IS NULL;
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.
select * from minister right outer join spd_politiker on minister.Name = spd_politiker.Name;
| 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
Ein 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:
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;
| 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.
Jo, sehr gut die verschiedenen joins erklärt. Ich fand die Seite http://www.sqlexikon.de auch ganz hilfreich, gut v.A. für SQL-Anfänger.
Vielen Dank, hat mir sehr geholfen!
Gern geschehen!
Vielleicht sollte ich irgendwann einmal die benannten Politiker in diesem Tutorial aktualisieren…
Vielen Dank, super aufgearbeitet, hat mir sehr geholfen
Sehr aufschlussreich geschrieben.
Jetzt kann meine Klausur kommen
Großes Lob
Prima erklärt mit einem lebensnahen und einfach nachvollziehbaren Beispiel. Klasse!
Supeeer !!! Weiter so…!!
[...] Angst des Papstes vor dem Volk«, »Die Angst des Erfolgreichen vor dem Fall«, »Die Angst des Programmierers vor dem SQL-Join«, »Die Angst des Pfarrers vor dem Glaubensbekenntnis«, »Die Angst der Giraffe vor [...]
Sehr, sehr hilfreich! Habs nun endlich mal verstanden, und hoffe es hilft mir auch über die mündliche Informatik-Abiturprüfung hinaus
Viele Dank!
Eine sehr hilfreiche Seite, weil es wirklich einfach und verständlich erklärt ist!
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
)