Was ist ein JOIN?
Von einem JOIN sprechen wir dann, wenn wir Spalten aus mehreren Tabellen nehmen und damit eine Abfrage erstellen. Wir verbinden (to JOIN) quasi zwei Tabellen miteinander*
* Nicht zu verwechseln mit einer UNION-Abfrage, bei welcher wir aus den Datensätzen zweier Tabellen eine neue grosse Tabelle mit Datensätzen aus beiden Tabellen machen. UNION-Abbfragen schauen wir hier nicht an.
Wissen Sie noch?
Erinnern Sie sich an die Listen der Kund*innen, welche immer nur eine doofe Nummer als Land angezeigt hat?
Bei den ersten Abfragen, als Sie alle Personen der Schweiz anzeigen wollten, mussten Sie jeweils ein Kriterium der folgenden Art hinschreiben:
WHERE tLandID = 756
Sie mussten quasi immer eine Liste mit allen Ländern auf dem Tisch liegen haben, um nachschlagen zu können, welche LandID wohl zu welchem Landesname gehört:
Das kann's ja irgendwie nicht sein…
Die folgende Liste wäre doch viel leserlicher, oder?
Was ist nun ein JOIN?
Ein JOIN ist die Verbindung von zwei Tabellen. Im obigen Beispiel verbinden wir die beiden Tabellen "tblKunden" und "tblLaender" miteinander.
Diese Verbindung muss über zwei Attribute erfolgen, welche zusammenpassen. In diesem Fall ist es jeweils das Attribut "tLandID". Das Ganze kann man auch grafisch darstellen:
Mit dieser Verbindung sind wir nun in der Lage, in einer Abfrage nicht nur Attribute von der linken Tabelle, sondern auch solche von der rechten Tabelle auszugeben.
Das Attribut "tLandID" in der linken Tabelle interessiert uns nämlich in der Regel überhaupt nicht. Wir wollen in der Praxis nicht mit Nummern hantieren. Und unsere Chefin will auch eine anständige Liste mit den ausgeschriebenen Landesnamen.
Wir schreiben also nicht mehr folgendes:
SELECT tNachname, tVorname, tLandID...
sondern:
SELECT tNachname, tVorname, tLandesname...
Damit dies aber möglich ist, müssen wir die beiden Tabellen verbinden.
Das geht im Grundsatz wie folgt. Erster Schritt:
SELECT tNachname, tVorname, tLandesname FROM tblKunden JOIN tblLaender
Nach der FROM-Klausel braucht es eben noch dieses "JOIN tblLaender".
Da wir aber noch angeben müssen, über welche beiden Attribute die Tabellen verbunden werden sollen, braucht es noch eine weitere einfache Zeile:
SELECT tNachname, tVorname, tLandesname FROM tblKunden JOIN tblLaender ON tblKunden.tLandID = tblLaender.tLandID
Das wars auch bereits.😎😂
Arten von JOINS
Nun gibt es verschiedene Arten von JOINS. Konkret heisst das, Sie können die beiden Tabellen auf unterschiedliche Arten miteinander verknüpfen resp. verbinden.
Also, verbunden sind sie jeweils gleich, aber man kann steuern, welche Datensätze konkret ausgegeben werden.
In der Literatur werden Tabellen in der Regel als Mengen und ein JOIN als Mengenoperation von zwei Mengen dargestellt. Das ist für Sie nichts Neues.
Sie sollten die folgenden vier Arten von JOINS kennen:
Diese besagen Folgendes:
- INNER JOIN: gib alle Datensätze aus, bei welchen in der linken wie auch in der rechten Tabelle ein Repräsentant (in den verbundenen Attributen) vorhanden ist. Das ist die Schnittmenge
- LEFT OUTER JOIN: liste sämtliche Datensätze der linken Tabelle auf, egal, ob in der rechten Tabelle die ID in der verbundenen Spalte übereinstimmt
- RIGHT OUTER JOIN: liste sämtliche Datensätze der rechten Tabelle auf, egal, ob in der linken Tabelle die ID in der verbundenen Spalte übereinstimmt
- FULL OUTER JOIN: theoretisch lustig, in der Praxis nicht relevant. Liste sämtliche Datensätze der linken Tabelle und sämtliche Datensätze der rechten Tabelle auf, unabhängig davon, ob eine Verbindung zwischen den Tabellen besteht
Es existieren noch weitere kuriose JOIN-Varianten, die wir hier aber nicht behandeln.
Die folgenden Beschreibungen beziehen sich immer konkret auf die folgenden zweiTabellen:
INNER JOIN
DER SQL-Befehl ist wie oben beschrieben. Als Schlüsselbegriff verwenden Sie hier "INNER JOIN":
SELECT tKundenID, tNachname, tVorname, tAnID FROM tblKunden INNER JOIN tblAnreden ON tblKunden.tAnID = tblAnreden.tAnredeID;
In diesem Beispiel geben wir das Attribut "tAnrede" nicht aus, sondern nur "tAnID". Und das sieht wie folgt aus:
Links sehen Sie, was der SQL-Befehl als Ausgabe liefert. Rechts sehen Sie die originalen Tabellen.
Aufgabe
Vergleichen Sie diese Liste mit der originalen Kundentabelle rechts. Wie unterscheiden sie sich?
Warum?
Und in der Praxis?
Wie gesagt, Ihre Chefin möchte gerne die folgende Liste haben:
Das heisst, Sie geben die Spalte "tAnID" nicht aus, sondern die Spalte "tAnrede".
In der Praxis ist es aber trotzdem so, dass Sie während der Entwicklung Ihres SQL-Befehls auch die ID-Spalten häufig angeben, um zu kontrollieren, ob Ihr SQL-Befehl stimmt.
Beim INNER JOIN ist das noch nicht sonderlich relevant, beim LEFT oder RIGHT OUTER JOIN dann hingegen schon.
LEFT OUTER JOIN
Das Einzige, was sich im folgenden SQL-Befehl geändert hat, ist das JOIN-Statement. Statt "INNER JOIN" steht nun "LEFT OUTER JOIN":
SELECT tKundenID, tNachname, tVorname, tAnID FROM tblKunden LEFT OUTER JOIN tblAnreden ON tblKunden.tAnID = tblAnreden.tAnredeID;
Die Ausgabe sieht nun wie folgt aus:
Aha, nun haben wir plötzlich wieder sämtliche Kund*innen auf der Liste (10 Personen). Schauen Sie nochmals das Mengendiagramm oben an. Das stimmt überein, nicht? Einfach die ganze linke Tabelle wird ausgegeben.
Interessant wird es erst dann, wenn wir nicht das Attribut "tAnID" der Tabelle "tblKunden" ausgeben, sondern das Feld "tAnrede" der Tabelle "tblAnreden".
Aufgabe
Überlegen Sie nun, ohne zu spicken, was der folgende SQL-Befehl ausgibt:
SELECT tKundenID, tNachname, tVorname, tAnID, tAnredeID FROM tblKunden LEFT OUTER JOIN tblAnreden ON tblKunden.tAnID = tblAnreden.tAnredeID;
RIGHT OUTER JOIN
Nun ändern wir das LEFT OUTER JOIN in ein RIGHT OUTER JOIN:
SELECT tKundenID, tNachname, tVorname, tAnID FROM tblKunden RIGHT OUTER JOIN tblAnreden ON tblKunden.tAnID = tblAnreden.tAnredeID;
Die Ausgabe ist hingegen ein wenig verwirrend:
Es ist schwer verständlich, woher diese vier NULL-Zeilen her kommen.
Hier macht es wirklich Sinn, dass wir nun auch die Spalte "tAnredeID" auch mit ausgeben. Dann sieht die Ausgabe wie folgt aus:
Jetzt macht der RIGHT OUTER JOIN eher Sinn. Jetzt werden sämtliche Datensätze der Tabelle "tblAnreden" (die rechte Tabelle) angezeigt. Und dort, wo möglich, werden die Datensätze der linken Tabelle ("tblKunden") angezeigt.
- Konkret heisst das, bei den Anreden mit den IDs 1, 5, 7, 9 und 10 hat es offensichtlich keine Kund*innen.
- Zudem beachten Sie, dass die beiden Kunden Nr. 2 und Nr. 9 hier fehlen. Das ist korrekt so, wenn Sie das Mengendiagramm oben anschauen.
RIGHT OUTER JOIN umdrehen
Sie können einen RIGHT OUTER JOIN, bei welchem die Tabelle "tblKunden" links ist, auch umdrehen in einer LEFT OUTER JOIN, bei welchem die Tabelle "tblAnreden" links ist:
SELECT tKundenID, tNachname, tVorname, tAnID, tAnredeID FROM tblAnreden LEFT OUTER JOIN tblKunden ON tblAnreden.tAnredeID = tblKunden.tAnID;
Das ergibt die gleichen Daten als Ausgabe, einfach ein wenig anders sortiert:
FULL OUTER JOIN
SELECT tKundenID, tNachname, tVorname, tAnID, tAnredeID FROM tblKunden FULL OUTER JOIN tblAnreden ON tblAnreden.tAnredeID = tblKunden.tAnID;
Jetzt werden sämtliche Datensätze von beiden Tabellen ausgegeben:
Beachten Sie, dass im Gegensatz zum RIGHT OUTER JOIN von vorhin nun die beiden Kunden Nr. 2 und Nr. 9 wieder auftauchen, obwohl sie keine passende Anrede-ID aufweisen.
Verbinden Sie die korrekten Attribute!
Achten Sie drauf, dass Sie die korrekten beiden Attribute miteinander verbinden, sonst kriegen Sie komplett falsche Daten raus!
Folgendes ist ohne Probleme möglich:
Schauen Sie sich den SQL-Befehl an:
SELECT tNachname, tVorname, tLandesname FROM tblKunden JOIN tblLaender ON tblKunden.tAnID = tblLaender.tLandID
Was ist hier konkret falsch?
Auch die Ausgabe der Daten ist dann ein wenig verdächtig (zumindest, wenn Sie mit der Zeit wissen, in welchen Ländern Ihre Kund*innen leben):
Das waren vorher nicht NULL-Werte. In der Spalte "tAnID" der Tabelle "tblKunden" steht ja entweder ein leerer String oder die Zahl 17 drin. Und beides sind keine NULL-Werte. Wenn SQL hingegen diese beiden Werte in der Tabelle "tblAnreden" suchen gehen muss, findet es sie nicht. Deshalb werden diesmal NULL-Werte zurückgegeben.