20
Okt

Die Angst des Programmierers vor dem SQL-Join

categories 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

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.

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

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.

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
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:

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.

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!

Kommentare

Comments (26) - “Die Angst des Programmierers vor dem SQL-Join”

  1. tres_chef am 27.04.2008 um %H:%M Uhr 

    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.

  2. Hannes Umbreit am 10.03.2009 um %H:%M Uhr 

    Vielen Dank, hat mir sehr geholfen!

  3. Björn am 10.03.2009 um %H:%M Uhr 

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

  4. BOBmoraine am 25.05.2009 um %H:%M Uhr 

    Vielen Dank, super aufgearbeitet, hat mir sehr geholfen

  5. Ama am 27.06.2009 um %H:%M Uhr 

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

  6. Thorsten am 05.02.2010 um %H:%M Uhr 

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

  7. Stefano am 07.06.2011 um %H:%M Uhr 

    Supeeer !!! Weiter so…!!

  8. Phraseologische Betrachtungen über diverse Ängste | Begleitschreiben am 10.03.2012 um %H:%M Uhr 

    […] 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 […]

  9. Watte am 20.05.2012 um %H:%M Uhr 

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

  10. Denise am 27.08.2012 um %H:%M Uhr 

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

  11. Christoph Koenig am 27.03.2013 um %H:%M Uhr 

    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
    )

  12. Stephan am 10.07.2013 um %H:%M Uhr 

    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

  13. Björn am 11.07.2013 um %H:%M Uhr 

    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!

  14. Carsten Guddat am 19.09.2013 um %H:%M Uhr 

    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?

  15. Björn am 19.09.2013 um %H:%M Uhr 

    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.

  16. Lars am 21.11.2013 um %H:%M Uhr 

    Eine durchaus gelungene Anleitung:). Ich verstehe auch nicht, warum sich viele vor der join-Thematik scheuen. Erleichtert den SQL-Alltag schließlich ungemein.
    Mein Favorit (zwar auf Englisch, aber dennoch sehr schön geschildert und verbildlicht):
    http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins

    Beste Grüße,
    Lars

  17. Rüdiger am 11.06.2014 um %H:%M Uhr 

    Bravo,
    endlich habe ich es kapiert… Klasse Anleitung, Respekt

  18. Fuci2022 am 15.06.2014 um %H:%M Uhr 

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

  19. Kristian am 04.07.2014 um %H:%M Uhr 

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

  20. Steffen am 05.08.2014 um %H:%M Uhr 

    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

  21. Björn am 05.08.2014 um %H:%M Uhr 

    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.

  22. Steffen am 06.08.2014 um %H:%M Uhr 

    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

  23. Björn am 06.08.2014 um %H:%M Uhr 

    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

  24. Steffen am 06.08.2014 um %H:%M Uhr 

    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

  25. Björn am 06.08.2014 um %H:%M Uhr 

    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

  26. Stefan Ganz am 05.09.2014 um %H:%M Uhr 

    Vielen Dank,
    habe nach einem SQL-Statement gesucht, dass mir nicht die Schnittmenge liefert und das hat mit left outer join prima funktioniert.
    Beste Grüße

Hinterlasse einen Kommentar!