Als SQL-JOIN (auf Deutsch: Verbund) be­zeich­net man eine Operation in re­la­tio­na­len Da­ten­ban­ken, die Abfragen über mehrere Da­ten­bank­ta­bel­len er­mög­licht. JOINs führen Daten zusammen, die in un­ter­schied­li­chen Tabellen ge­spei­chert sind, und geben diese in ge­fil­ter­ter Form in einer Er­geb­nis­ta­bel­le aus.

Das Prinzip des SQL-JOINs basiert auf der gleich­na­mi­gen Operation der re­la­tio­na­len Algebra – einer Kom­bi­na­ti­on aus kar­te­si­schem Produkt und Selektion. Welche Daten der Aus­gangs­ta­bel­len in die Ergebnis-Tabelle über­nom­men werden, bestimmt der Anwender durch die Wahl eines JOIN-Typs und durch die De­fi­ni­ti­on einer Se­lek­ti­ons­be­din­gung.

Wir führen Sie in die ma­the­ma­ti­schen Grund­la­gen von SQL-JOINs ein, stellen ver­schie­de­ne JOIN-Typen gegenüber und zeigen Ihnen anhand von Pra­xis­bei­spie­len, wie Sie JOINs im Rahmen von Da­ten­bank­ab­fra­gen via SQL umsetzen.

Tipp

Der Artikel zu SQL-JOIN setzt die Kenntnis be­stimm­ter Konzepte des re­la­tio­na­len Da­ten­bank­mo­dells voraus, ins­be­son­de­re was Re­la­tio­nen, Tupel, Attribute oder Schlüssel betrifft. Eine ent­spre­chen­de Ein­füh­rung bietet unser Grund­la­gen­ar­ti­kel zu re­la­tio­na­len Da­ten­ban­ken.

Wie funk­tio­nie­ren SQL-JOINs?

An­schau­lich dar­stel­len lässt sich das Grund­prin­zip des SQL-JOINs, wenn man sich die Da­ten­bank­ope­ra­ti­on über deren Teil­ope­ra­tio­nen herleitet. Grundlage eines jeden JOINs sind folgende Ope­ra­tio­nen der re­la­tio­na­len Algebra:

  • Kar­te­si­sches Produkt
  • Selektion

Das kar­te­si­sche Produkt

Das kar­te­si­sche Produkt (auch Kreuz­pro­dukt) ist eine Operation der Men­gen­leh­re, bei der zwei oder mehr Mengen mit­ein­an­der verknüpft werden. Im re­la­tio­na­len Da­ten­bank­mo­dell kommt das kar­te­si­sche Produkt zum Einsatz, um Tupel-Mengen in Form von Tabellen mit­ein­an­der zu verbinden. Das Ergebnis dieser Operation ist wiederum eine Menge ge­ord­ne­ter Tupel, bei der jedes Tupel aus einem Element jeder Aus­gangs­men­ge besteht.

Als Operator für das kar­te­si­sche Produkt kommt in der re­la­tio­na­len Algebra das Mul­ti­pli­ka­ti­ons­zei­chen (×) zum Einsatz.

Dazu ein Beispiel:

Das kar­te­si­sche Produkt A × B der beiden Mengen A = {x, y, z} und B = {1, 2, 3} ist:

A × B = {(x,1), (x,2), (x,3), (y,1), (y,2), (y,3), (z,1), (z,2), (z,3)}

Ver­an­schau­li­chen lässt sich die Rechnung anhand folgender Grafik:

Zu beachten ist dabei die Rei­hen­fol­ge der Paar­bil­dung. Das kar­te­si­sche Produkt A × B ent­spricht bei­spiels­wei­se nicht derselben Menge wie das kar­te­si­sche Produkt von B × A.

A × B = {(x,1), (x,2), (x,3), (y,1), (y,2), (y,3), (z,1), (z,2), (z,3)}

B × A = {(1,x), (1,y), (1,z), (2,x), (2,y), (2,z), (3,x), (3,y), (3,z)}

In der SQL-Ter­mi­no­lo­gie wird eine Operation, bei der das kar­te­si­sche Produkt aus zwei Da­ten­bank­ta­bel­len gebildet wird, als CROSS JOIN be­zeich­net. In der Praxis kommen CROSS JOINs aufgrund der un­ge­fil­ter­ten Er­geb­nis­men­ge nur selten zum Einsatz.

Die Selektion

Bei der Selektion handelt es sich um eine Operation der re­la­tio­na­len Algebra, die es er­mög­licht, bestimmte Tupel einer Aus­gangs­men­ge aus­zu­wäh­len und als Er­geb­nis­men­ge aus­zu­ge­ben. Welche Tupel in die Er­geb­nis­men­ge auf­ge­nom­men werden, lässt sich über einen Ver­gleichs­aus­druck festlegen. Das Ergebnis der Selektion ist somit eine Menge von Tupeln, die die im Ver­gleichs­aus­druck de­fi­nier­te Se­lek­ti­ons­be­din­gung erfüllen. Als Operator kommt der grie­chi­sche Buchstabe Sigma (σ) zum Einsatz. Die Operation wird fol­gen­der­ma­ßen notiert:

σF (R)

Der Platz­hal­ter „F“ ent­spricht dem Ver­gleichs­aus­druck, einer Formel aus logischen Prä­di­ka­ten, die die Se­lek­ti­ons­be­din­gung de­fi­nie­ren. R steht für den zu se­lek­tie­ren­den Da­ten­be­stand. Al­ter­na­tiv bietet sich die lineare Schreib­wei­se R[F] an.

Zum For­mu­lie­ren von Se­lek­ti­ons­be­din­gun­gen stehen die üblichen Ver­gleichs­ope­ra­to­ren zur Verfügung: bei­spiels­wei­se gleich (=), größer (>) oder kleiner (<).

Wir erläutern die Selektion anhand eines Beispiels, das wir bereits im Grund­la­gen­text zum re­la­tio­na­len Da­ten­bank­mo­dell ein­ge­führt haben. Folgende Tabelle zeigt fiktive Per­so­nal­da­ten, die ein Un­ter­neh­men zu seinen Mit­ar­bei­tern erfasst haben könnte. Für jeden Mit­ar­bei­ter sind die Per­so­nal­num­mer (m_id), Angaben zum Namen (nachname, vorname), zur So­zi­al­ver­si­che­rungs­num­mer (svn), zur Adresse (str, plz, ort) sowie zum zu­ge­wie­se­nen Fir­men­wa­gen (kfz_id) angegeben.

Tabelle: mit­ar­bei­ter
m_id nachname vorname svn str nr plz ort kfz_id
1 Schmidt Udo 25 120512 S 477 Haupt­stra­ße 1 11111 Mus­ter­hau­sen 3
2 Müller Wolfgang 25 100615 M 694 Bahn­hof­stra­ße 2 22222 Mus­ter­heim 1
3 Meyer Günther 25 091225 M 463 Am Markt­platz 3 33333 Mus­ter­fel­de 1
4 Krause Helmut 25 170839 K 783 Waldweg 4 44444 Mus­ter­wal­de 2

Möchten wir die Tabelle „mit­ar­bei­ter“ nun so se­lek­tie­ren, dass lediglich die Mit­ar­bei­ter angezeigt werden, die den Fir­men­wa­gen mit der kfz_id 1 fahren, könnten wir fol­gen­der­ma­ßen vorgehen:

σkfz_id=1(mit­ar­bei­ter)

Wir rufen lediglich die Tupel ab, bei denen der Wert in der Spalte kfz_id gleich 1 ist.

Das Ergebnis ent­spricht folgender Tabelle.

Tabelle: mit­ar­bei­ter (se­lek­tiert)
m_id nachname vorname svn str nr plz ort kfz_id
2 Müller Wolfgang 25 100615 M 694 Bahn­hof­stra­ße 2 22222 Mus­ter­heim 1
3 Meyer Günther 25 091225 M 463 Am Markt­platz 3 33333 Mus­ter­fel­de 1

In der Da­ten­bank­spra­che SQL werden Se­lek­ti­ons­be­din­gun­gen mithilfe des Befehls WHERE definiert.

SELECT * FROM mitarbeiter WHERE mitarbeiter.kfz_id = 1;

Erfüllt ein Tupel die Bedingung kfz_id = 1, sollen für diesen die Werte aller Spalten aus­ge­ge­ben werden.

Hinweis

Der Asterisk (*) steht in der SQL-Sytax stell­ver­tre­tend für alle Spalten einer Tabelle.

Kom­bi­na­ti­on aus kar­te­si­schem Produkt und Selektion

Alle gängigen JOIN-Typen kom­bi­nie­ren das kar­te­si­sche Produkt mit einer Se­lek­ti­ons­be­din­gung. Um eine solche Da­ten­bank­ope­ra­ti­on zu erklären, re­du­zie­ren wir die Tabelle „mit­ar­bei­ter“ der An­schau­lich­keit halber auf vier Spalten. Zudem führen wir die Tabelle kfz ein, in der Detail-In­for­ma­tio­nen zum Fuhrpark des Un­ter­neh­mens ge­spei­chert werden.

Beide Tabellen sind über eine Fremd­schlüs­sel­be­zie­hung mit einander verknüpft. Der Pri­mär­schlüs­sel der Tabelle „kfz“ (die kfz_id) fungiert in der Tabelle „mit­ar­bei­ter“ als Fremd­schlüs­sel.

Tabelle: mit­ar­bei­ter
m_id nachname vorname kfz_id
1 Schmidt Udo 3
2 Müller Wolfgang 1
3 Meyer Günther 1
4 Krause Helmut 2
Tabelle: kfz
kfz_id marke modell kenn­zei­chen baujahr hu
1 VW Caddy B KH 778 2016 18.12.2018
2 Opel Astra B PO 654 2010 12.08.2019
3 BMW X6 B MW 780 2017 01.09.2018
Hinweis

Die Aus­la­ge­rung von In­for­ma­tio­nen in ver­schie­de­ne Da­ten­bank­ta­bel­len ist ein grund­le­gen­des Konzept des re­la­tio­na­len Da­ten­bank­mo­dells. Die Vorteile eines solchen Da­ten­bank­de­signs sowie dessen Umsetzung the­ma­ti­sie­ren wir in einem wei­ter­füh­ren­den Artikel zur Nor­ma­li­sie­rung von re­la­tio­na­len Da­ten­ban­ken.

Möchte man die beiden Tabellen zu­sam­men­füh­ren und gleich­zei­tig relevante Tupel se­lek­tie­ren, kom­bi­niert man die zuvor ein­ge­führ­ten Da­ten­bank­ope­ra­tio­nen:

σkfz_id=kfz_id(mit­ar­bei­ter × kfz)

Dabei wird zunächst das kar­te­si­sche Produkt mit­ar­bei­ter × kfz gebildet. Das (Zwischen-)Ergebnis ist ein CROSS JOIN – eine Er­geb­nis­ta­bel­le, in der jeder Tupel der Tabelle „mit­ar­bei­ter“ mit jedem Tupel der Tabelle „kfz“ kom­bi­niert wird.

Tabelle: Kar­te­si­sches Produkt „mit­ar­bei­ter“ × „kfz“
m_id nachname vorname mit­ar­bei­ter.kfz_id kfz.kfz_id marke modell kenn­zei­chen baujahr hu
1 Schmidt Udo 3 1 VW Caddy B KH 778 2016 18.12.2018
1 Schmidt Udo 3 2 Opel Astra B PO 654 2010 12.08.2019
1 Schmidt Udo 3 3 BMW X6 B MW 780 2017 01.09.2018
2 Müller Wolfgang 1 1 VW Caddy B KH 778 2016 18.12.2018
2 Müller Wolfgang 1 2 Opel Astra B PO 654 2010 12.08.2019
2 Müller Wolfgang 1 3 BMW X6 B MW 780 2017 01.09.2018
3 Meyer Günther 1 1 VW Caddy B KH 778 2016 18.12.2018
3 Meyer Günther 1 2 Opel Astra B PO 654 2010 12.08.2019
3 Meyer Günther 1 3 BMW X6 B MW 780 2017 01.09.2018
4 Krause Helmut 2 1 VW Caddy B KH 778 2016 18.12.2018
4 Krause Helmut 2 2 Opel Astra B PO 654 2010 12.08.2019
4 Krause Helmut 2 3 BMW X6 B MW 780 2017 01.09.2018

An­schlie­ßend werden lediglich die Tupel se­lek­tiert, bei denen die kfz_id der Tabelle „kfz“ mit der kfz_id der Tabelle „mit­ar­bei­ter“ über­ein­stimmt. Se­lek­ti­ons­be­din­gung ist somit, dass der Fremd­schlüs­sel der Tabelle „mit­ar­bei­ter“ dem Pri­mär­schlüs­sel der Tabelle „kfz“ ent­spricht.

Als (End-)Ergebnis erhalten wir eine Tabelle, die beide Aus­gangs­ta­bel­len ohne Red­un­dan­zen zu­sam­men­führt.

Tabelle: JOIN über „mit­ar­bei­ter“ und „kfz“
m_id nachname vorname mit­ar­bei­ter.kfz_id kfz.kfz_id marke modell kenn­zei­chen baujahr hu
1 Schmidt Udo 3 3 BMW X6 B MW 780 2017 01.09.2018
2 Müller Wolfgang 1 1 VW Caddy B KH 778 2016 18.12.2018
3 Meyer Günther 1 1 VW Caddy B KH 778 2016 18.12.2018
4 Krause Helmut 2 2 Opel Astra B PO 654 2010 12.08.2019

Als Kom­bi­na­ti­on aus kar­te­si­schem Produkt und an­schlie­ßen­der Selektion fassen JOINs beide Ope­ra­tio­nen in einer ge­mein­sa­men zusammen. Als Operator wird das Bowtie-Symbol (⋈) genutzt.

Es gilt somit:

σkfz_id=kfz_id(mit­ar­bei­ter × kfz) := mit­ar­bei­ter⋈kfz_id=kfz_idkfz

Die Operation σkfz_id=kfz_id(mit­ar­bei­ter × kfz) ent­spricht einem JOIN über die Tabellen „mit­ar­bei­ter“ und „kfz“ mit der Vor­aus­set­zung kfz_id=kfz_id.

Über­tra­gen auf die SQL-Syntax ent­sprä­che die oben dar­ge­stell­te Operation folgendem Statement:

SELECT * FROM mitarbeiter INNER JOIN kfz ON mitarbeiter.kfz_id = kfz.kfz_id;

Der INNER JOIN ist einer der wich­tigs­ten JOINs, die im Rahmen von Da­ten­bank­ab­fra­gen zum Einsatz kommen. Mitunter werden jedoch spezielle JOIN-Typen benötigt, um das ge­wünsch­te Ergebnis zu erreichen.

SQL-JOIN-Typen

Im re­la­tio­na­len Da­ten­bank­mo­dell werden un­ter­schied­li­che SQL-JOIN-Typen genutzt, die es er­mög­li­chen, Abfragen über einen Verbund von Da­ten­bank­ta­bel­len aus­zu­füh­ren. Vor­aus­set­zung dafür ist, dass die aus­ge­wähl­ten Tabellen über Fremd­schlüs­sel­be­zie­hun­gen mit­ein­an­der verknüpft sind.

Zu den wich­tigs­ten JOIN-Typen gehören folgende:

  • INNER JOINs: Bei einem INNER JOIN handelt es sich um eine ge­fil­ter­te Form des CROSS JOINs, bei der in der Er­geb­nis­men­ge nur die Tupel beider Aus­gangs­ta­bel­len zu­sam­men­ge­führt werden, die die vom Anwender de­fi­nier­te Se­lek­ti­ons­be­din­gung erfüllen.

  • OUTER JOINs: Der OUTER JOIN stellt eine Er­wei­te­rung des INNER JOINS dar. Er­geb­nis­men­ge eines OUTER JOINS enthält die Tupel beider Aus­gangs­ta­bel­len, die die vom Anwender de­fi­nier­te Se­lek­ti­ons­be­din­gung erfüllen, wie auch alle rest­li­chen Tupel der ersten Tabelle, der zweiten Tabelle oder beider Tabellen. OUTER JOINS werden ent­spre­chend als LEFT OUTER JOIN, RIGHT OUTER JOIN oder FULL OUTER JOIN rea­li­siert.
Tipp

Eine de­tail­lier­te Be­schrei­bung von INNER JOINs und OUTER JOINs finden Sie in den wei­ter­füh­ren­den Artikeln zu diesen JOIN-Typen.

Ver­deut­li­chen lassen sich die Un­ter­schie­de zwischen INNER JOINs und den ver­schie­de­nen Varianten des OUTER JOINS durch Men­gen­dia­gram­me. Folgende Grafik ist eine bildliche Dar­stel­lung der vor­ge­stell­ten JOIN-Typen:

Un­ab­hän­gig von der Un­ter­schei­dung zwischen INNER JOIN und OUTER JOIN lassen sich SQL-JOINs zudem als folgende JOIN-Typen klas­si­fi­zie­ren:

  • EQUI JOIN
  • NON EQUI JOIN
  • SELF JOIN

INNER JOINs und OUTER JOINs lassen sich als EQUI JOINs und NON EQUI JOINs umsetzen. Alle bisher vor­ge­stell­ten JOIN-Beispiele stellen EQUI JOINs dar. EQUI JOINs sind dadurch ge­kenn­zeich­net, dass sie aus­schließ­lich das Gleich­heits­zei­chen als Ver­gleichs­ope­ra­tor (=) zulassen.

Die Se­lek­ti­ons­be­din­gung eines EQUI JOINs ist somit immer die Gleich­heit von Spalten-Werten.

Prin­zi­pi­ell sind JOINS jedoch (ebenso wie die Selektion in der re­la­tio­na­len Algebra) nicht auf die Gleich­heit von Spalten be­schränkt. Mögliche Ver­gleichs­ope­ra­to­ren sind:

Ver­gleichs­ope­ra­tor Bedeutung
= gleich
< kleiner als
> größer als
kleiner oder gleich
größer oder gleich
<> ungleich
!= ungleich

Seit SQL-92 bietet die Da­ten­bank­spra­che mit dem Schlüs­sel­wort USING eine Kurz­schreib­wei­se für EQUI JOINS. Diese setzt jedoch voraus, dass die be­tref­fen­den Spalten den gleichen Namen haben, was nicht zwangs­läu­fig der Fall sein muss.

Das folgende Beispiel zeigt zwei un­ter­schied­li­che SQL-State­ments, die zum selben Ergebnis führen. Im ersten Statement de­fi­nie­ren wird die JOIN-Bedienung mithilfe des Schlüs­sel­worts ON explizit. Beim zweiten Statement verwenden wir die Kurz­schreib­wei­se mit dem Schlüssel USING.

SELECT * FROM mitarbeiter INNER JOIN kfz ON mitarbeiter.kfz_id = kfz.kfz_id;
SELECT * FROM mitarbeiter INNER JOIN kfz USING kfz_id;

NON EQUI JOINs hingegen schließen Ope­ra­tio­nen auf Basis der Gleich­heit von Spalten aus. Es sind somit alle Ver­gleichs­ope­ra­tio­nen mit Ausnahme des Gleich­heits­zei­chens (=) erlaubt.

Hinweis

Da Be­zie­hun­gen in re­la­tio­na­len Da­ten­ban­ken in der Regel über die Gleich­heit von Primär- und Fremd­schlüs­sel definiert werden, sind NON EQUI JOIN im re­la­tio­na­len Da­ten­bank­mo­dell von nach­ran­gi­ger Bedeutung. Nicht zuletzt deshalb, weil diese ebenso wie bei CROSS JOINs oft zu sehr vielen Er­geb­nis­da­ten­sät­zen führen.

Ein SELF JOIN schließ­lich ist eine Son­der­form des SQL-JOINs, bei der eine Da­ten­bank­ta­bel­le mit sich selbst verknüpft wird. Prin­zi­pi­ell lässt sich jeder JOIN-Typ als SELF JOIN ausführen.

Werden zwei Tabellen über gleich­na­mi­ge Spalten verknüpft, spricht man von einem NATURAL JOIN. Ein NATURAL JOIN wird über das gleich­na­mi­ge Schlüs­sel­wort stan­dard­mä­ßig als INNER JOIN rea­li­siert. Auf diesen JOIN-Typ fest­ge­legt sind NATURAL JOINs hingegen nicht. Möglich ist ebenso ein NATURAL LEFT OUTER JOIN oder ein NATURAL RIGHT OUTER JOIN.

Da die Ver­knüp­fung bei NATURAL JOINs über gleich­na­mi­ge Spalten erfolgt, werden die je­wei­li­gen Werte in der Er­geb­nis­men­ge nicht doppelt aus­ge­ge­ben, sondern zu einer ge­mein­sa­men Spalte zu­sam­men­ge­führt. Beispiele zu NATURAL JOINs finden Sie in den wei­ter­füh­ren­den Artikeln zu INNER JOINs und OUTER JOINs.

Zum Hauptmenü