Join (SQL)
Ein SQL-Join verknüpft eine oder mehrere Spalten verschiedener Tabellen einer relationalen Datenbank, um das Ergebnis als in Tabellenform auszugeben oder weiterzuverarbeiten. Ein JOIN
ermöglicht das Verknüpfen der Spalten mehrerer Tabellen, die gemeinsame Werte besitzen. Im Sonderfall werden die Spalten einer einzelnen Tabelle verbunden (Self-Join).
Der ANSI-Standard für SQL beschreibt fünf Arten von JOIN
s: INNER
, LEFT OUTER
, RIGHT OUTER
, FULL OUTER
und CROSS
. Als Spezialfall kann eine Tabelle (Basistabelle, View oder gejointe Tabelle) ein JOIN
auf sich selbst durchführen (SELF JOIN
).
Ein Programmierer deklariert eine JOIN
-Anweisung, um mögliche Zeilen für einen Join zu identifizieren. Ein wahres Prädikat resultiert in der Ausgabe in einem entsprechenden Format, einem Datensatz oder einer temporären Tabelle.
Referenz-Tabelle
Relationale Datenbanken sind für gewöhnlich normalisiert um Duplikate, wie sie bei Entitätstypen mit "one-to-many"-Verknüpfungen bestehen, zu eliminieren. So kann zum Beispiel eine Abteilung mehrere Angestellte haben. Ein Join der Tabellen Abteilung und Angestellte ist eine effektive Möglichkeit, um eine neue Tabelle zu erstellen, welche alle Informationen beider Tabellen enthält.
Alle nachfolgenden Erklärungen über die verschiedenen Arten, Wirkweisen und die Prädikate von Joins verwenden die beiden weiter unten dargestellten Tabellen.
In den folgenden Tabellen ist die Spalte AbteilungID
der Tabelle Abteilung
(auch Abteilung.AbteilungID
genannt) der Primärschlüssel, während hingegen Angestellter.AbteilungID
den Fremdschlüssel auszeichnet.
Nachname | AbteilungID |
---|---|
Müller | 31 |
Schmidt | 33 |
Schneider | 33 |
Fischer | 34 |
Weber | 34 |
Meyer | NULL |
AbteilungID | AbteilungName |
---|---|
31 | Verkauf |
33 | Technik |
34 | Büro |
35 | Marketing |
Anmerkung: In der obigen Tabelle Angestellter wurde dem Angestellten "Meyer" noch keine Abteilung zugewiesen. Außerdem gehört kein Angestellter der Abteilung "Marketing" an.
Die folgende SQL-Anweisung erzeugt die zuvor genannten Tabellen:
CREATE TABLE Abteilung
(
AbteilungID INT Primary key,
AbteilungName VARCHAR(20)
);
CREATE TABLE Angestellter
(
Nachname VARCHAR(20),
AbteilungID INT references Abteilung(AbteilungID)
);
INSERT INTO Abteilung VALUES(31, 'Verkauf');
INSERT INTO Abteilung VALUES(33, 'Technik');
INSERT INTO Abteilung VALUES(34, 'Büro');
INSERT INTO Abteilung VALUES(35, 'Marketing');
INSERT INTO Angestellter VALUES('Müller', 31);
INSERT INTO Angestellter VALUES('Schmidt', 33);
INSERT INTO Angestellter VALUES('Schneider', 33);
INSERT INTO Angestellter VALUES('Fischer', 34);
INSERT INTO Angestellter VALUES('Weber', 34);
INSERT INTO Angestellter VALUES('Meyer', NULL);
CROSS JOIN
Ein CROSS JOIN
gibt das kartesische Produkt der Tabellenzeilen eines Joins wieder. Mit anderen Worten: Ein neuer Datensatz entsteht durch die Verknüpfung jeder Zeile der einen Tabelle mit jeder Zeile der anderen Tabelle.[1]
Beispiel eines expliziten CROSS JOIN
s:
SELECT *
FROM Angestellter CROSS JOIN Abteilung;
Beispiel eines impliziten CROSS JOIN
s:
SELECT *
FROM Angestellter, Abteilung;
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName | Abteilung.AbteilungID |
---|---|---|---|
Müller | 31 | Verkauf | 31 |
Schmidt | 33 | Verkauf | 31 |
Schneider | 33 | Verkauf | 31 |
Weber | 34 | Verkauf | 31 |
Fischer | 34 | Verkauf | 31 |
Meyer | NULL | Verkauf | 31 |
Müller | 31 | Technik | 33 |
Schmidt | 33 | Technik | 33 |
Schneider | 33 | Technik | 33 |
Weber | 34 | Technik | 33 |
Fischer | 34 | Technik | 33 |
Meyer | NULL | Technik | 33 |
Müller | 31 | Büro | 34 |
Schmidt | 33 | Büro | 34 |
Schneider | 33 | Büro | 34 |
Weber | 34 | Büro | 34 |
Fischer | 34 | Büro | 34 |
Meyer | NULL | Büro | 34 |
Müller | 31 | Marketing | 35 |
Schmidt | 33 | Marketing | 35 |
Schneider | 33 | Marketing | 35 |
Weber | 34 | Marketing | 35 |
Fischer | 34 | Marketing | 35 |
Meyer | NULL | Marketing | 35 |
Ein CROSS JOIN
verwendet kein Prädikat, um die Zeilen der gejointen Tabelle zu filtern. Eine zusätzliche WHERE
-Bedingung kann jedoch den CROSS JOIN
filtern, um ihn in einen INNER JOIN
umzuwandeln.
Der SQL:2011-Standard listet CROSS JOIN
s als Teil des optionalen F401-Pakets Extended joined table auf.
Ein typischer Einsatz sind Checks der Leistungsfähigkeit von Servern.
INNER JOIN

INNER JOIN
zweier Tabellen A und BFür einen INNER JOIN
müssen in jeder Zeile der zwei zu joinenden Tabellen übereinstimmende Spalten-Werte vorhanden sein. Software enthält oft diese Join-Operation, sie gilt aber nicht als beste Lösung für alle Probleme. Ein INNER JOIN
erstellt eine neue Ergebnis-Tabelle, indem er die Spalten-Werte der zwei Tabellen A und B aufgrund ihres Join-Prädikats miteinander verbindet. Die Abfrage vergleicht jede Zeile von Tabelle A mit jeder Zeile von Tabelle B, um alle Paare zu finden, die dem Join-Prädikat genügen. Besitzen diese Paare keine NULL-Werte, generieren sie eine vereinigte Ergebnis-Zeile.
Das Ergebnis eines Joins entspricht einem kartesischen Produkt (oder CROSS JOIN
) aller Zeilen der Tabellen A und B (jede Zeile der Tabelle A mit jeder Zeile der Tabelle B), bei welchem bei anschließender Ausgabe alle Zeilen dem Join-Prädikat genügen.
Gegenwärtige SQL-Umsetzungen verwenden für gewöhnlich Ansätze wie Hash-Join oder Sort-Merge-Join, da das Berechnen eines kartesischen Produkts viel langsamer wäre und zu viel Arbeitsspeicher benötigte.
In SQL sind zwei syntaktische Arten von Joins definiert: die "explizite" Join-Notation und die "implizite" Join-Notation. Die implizite Join-Notation gilt nicht mehr als Best practice, Datenbanksysteme unterstützen sie jedoch weiterhin. Die explizite Join-Notation verwendet das JOIN
-Schlüsselwort, optional mit dem INNER
-Schlüsselwort vorangestellt, um die Tabelle zu benennen, und das ON
-Schlüsselwort, um das Join-Prädikat zu definieren.
Beispiel für die explizite Join-Notation:
SELECT Angestellter.Nachname, Angestellter.AbteilungID, Abteilung.AbteilungName
FROM Angestellter
INNER JOIN Abteilung ON
Angestellter.AbteilungID = Abteilung.AbteilungID;
Ergebnis:
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName |
---|---|---|
Fischer | 34 | Büro |
Schmidt | 33 | Technik |
Weber | 34 | Büro |
Schneider | 33 | Technik |
Müller | 31 | Verkauf |
In der impliziten Join-Notation sind die zu joinenden Tabellen in der FROM
-Bedingung der SELECT
-Abfrage lediglich durch ein Komma getrennt. Mit einer zusätzlichen WHERE
-Bedingung auf den dadurch durchgeführten CROSS JOIN
sind weitere Filter-Prädikate möglich, die analog zur expliziten Join-Notation funktionieren.
Diese implizite Join-Notation führt zum gleichen Ergebnis wie die explizite Notation:
SELECT *
FROM Angestellter, Abteilung
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID;
Die Abfragen der obigen Beispiele joinen die Tabellen Angestellter und Abteilung, indem sie die gemeinsame Spalte AbteilungID verwenden. Passt die AbteilungID der Tabellen (das Join-Prädikat ist erfüllt), verbindet die Abfrage die Spalten Nachname, AbteilungID und AbteilungName der beiden Tabellen zu einer Ergebnis-Zeile. Bei nicht übereinstimmender AbteilungID, generiert sich keine neue Ergebniszeile. Das Ergebnis des Auswertungsplans der Abfrage sieht folgendermaßen aus:
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName | Abteilung.AbteilungID |
---|---|---|---|
Fischer | 34 | Büro | 34 |
Schmidt | 33 | Technik | 33 |
Weber | 34 | Büro | 34 |
Schneider | 33 | Technik | 33 |
Müller | 31 | Verkauf | 31 |
Der Angestellte "Meyer" und die Abteilung "Marketing" tauchen nach der Ausführung der Abfrage nicht als Ergebnisse auf. Keiner von beiden weist eine passende Zeile in der entsprechend anderen Tabelle auf: "Meyer" hat keine entsprechende Abteilung, und kein Angestellter hat die AbteilungId 35 ("Marketing"). Abhängig von den gewünschten Resultaten, ist dieses Verhalten ein simpler Bug, den das Ersetzen des INNER JOIN
durch einen OUTER JOIN
, fixt.
Bei einem Join zweier Tabellen, die NULL-Werte enthalten, ist besondere Vorsicht angebracht. Bei nicht übereinstimmender AbteilungID, generiert sich keine neue Ergebniszeile. In diesem Fall stimmt kein NULL-Wert mit einem anderen Wert überein (auch nicht mit dem NULL-Wert selbst). Die explizite Verwendung eines modifizierten Prädikats in der Join-Bedingung berücksichtigt diese Einträge, wobei bei Anwendung der restlichen Prädikatsbedingungen die Join-Spalten den Wert NOT NULL aufweisen müssen.
Der INNER JOIN
ist nur bei Datenbanken zuverlässig, die referentielle Integrität erzwingen oder in Fällen, in denen die Join-Spalten mit Sicherheit keine NULL-Werte enthalten. Viele transaktionsverarbeitende relationale Datenbanken basieren auf dem ACID-Prinzip-Standard für Datenupdates, um die Datenintegrität zu gewährleisten, weshalb INNER JOIN
s eine gute Wahl sind. Transaktionsdatenbanken haben jedoch meist erwünschte Join-Spalten, die NULL-Werte enthalten können. Manche reportende relationalen Datenbanken und Data-Warehouses verwenden Batch-Updates für ETL-Prozesse, die den Zwang zur Erhaltung der referentielle Integrität schwierig oder unmöglich machen, wodurch Join-Spalten mit NULL-Werten entstehen können, welche der Autor der SQL-Abfrage nicht verändern kann und welche bei einem INNER JOIN
s zu einem Verlust von Datensätzen führen kann, ohne dass es Anzeichen für Fehler gibt. Die Entscheidung für oder gegen einen INNER JOIN
hängt vom Datenbankdesign und den Besonderheiten der Datensätze ab. Ein INNER JOIN
kann für gewöhnlich einen LEFT OUTER JOIN
ersetzen, falls die Join-Spalten in einer Tabelle NULL-Werte enthalten.
Spalten mit NULL-Werten eignen sich nur für INNER JOIN
s, falls diese entsprechende Zeilen mit NULL-Werten entfernen sollen. In diesem Fall kann ein INNER JOIN
sogar schneller als ein OUTER JOIN
sein, da der Join und das Filtern ein einziger Schritt sind.
Andererseits kann ein INNER JOIN
bei einer hochvolumigen Abfrage in Kombination mit Datenbankfunktionen in einer WHERE-Bedingung zu verheerend langsamer Performance oder sogar zu einem Serverabsturz führen.[2][3][4]
Eine Funktion in einer WHERE-Bedingung kann dazu führen, dass eine Datenbank relativ kompakte Tabellenindizes ignoriert.
Unter Umständen liest die Datenbank die ausgewählten Spalten der beiden Tabellen aus und führt einen INNER JOIN
mit ihnen aus, bevor ein Filter mit Abhängigkeit von einem vorher berechneten Wert die Anzahl der Zeilen reduziert. Dies führt schließlich zu einer ineffizienten Prozessverarbeitung.
Sollte ein Join ein Ergebnis-Set generieren, das Master-Tabellen enthält, die zum Nachschlagen ganzer Text-Beschreibungen numerischer Kennzahlen dienen (Lookup-Tabelle), kann ein NULL-Wert in einem der Fremdschlüssel eine Löschung der gesamten Zeile aus dem Ergebnis-Set ohne Hinweis auf einen Fehler verursachen. Eine komplexe SQL-Abfrage, die eine oder mehrere INNER JOIN
s und mehrere OUTER JOIN
s enthält, birgt das gleiche Risiko für NULL-Werte in den verknüpften Spalten des INNER JOIN
s.
Ein Commit für SQL-Code, das NULL-Werte von INNER JOIN
s berücksichtigt, ist in zukünftigen Änderungen also Updates von Anbietern, Veränderungen am Design, Stapelverarbeitung außerhalb der Regeln der Datenvalidierung der Anwendung (wie Datenkonvertierung), Migrationen, Bulk-Importe und Merges, nicht vorgesehen.
Der folgende Abschnitt beschreibt die Unterteilung des INNER JOIN
s in EQUI JOIN
, als NATURAL JOIN
und CROSS JOIN
.
EQUI JOIN
Ein EQUI JOIN
ist ein vergleichsbasierter Join, welcher nur den Gleichheits-Vergleich im Join-Prädikat verwendet. Andere benutzte Vergleichsoperatoren (wie z. B.: <
) schließen einen EQUI JOIN
aus. Die obige Abfrage enthält bereits ein Beispiel für einen EQUI JOIN
:
SELECT *
FROM Angestellter JOIN Abteilung
ON Angestellter.AbteilungID = Abteilung.AbteilungID;
oder mit folgender Notation:
SELECT *
FROM Angestellter, Abteilung
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID;
Der SQL-92-Standard liefert eine optionale Kurznotation, um Spalten gleichen Namens mit dem USING
-Konstrukt zu beschreiben:[5]
SELECT *
FROM Angestellter INNER JOIN Abteilung USING (AbteilungID);
Das USING
-Konstrukt ist mehr als nur Syntaktischer Zucker, da das Resultat sich von der Abfrage mit explizitem Prädikat unterscheidet. Alle ausgegebenen Spalten der USING
-Liste haben einen unbestimmten Namen, statt je einem für jede Tabelle des Joins. Das obige Beispiel ergibt eine einzelne Spalte AbteilungID
und keine Angestellter.AbteilungID
- oder Abteilung.AbteilungID
-Spalte.
MS SQL Server und Sybase unterstützen die USING
-Bedingung nicht.
NATURAL JOIN
Der NATURAL JOIN
ist ein Spezialfall des EQUI JOIN
s. Der NATURAL JOIN
(⋈) ist eine Zweistellige Relation mit Notation R ⋈ S (R und S als Relationen). Das Kennzeichen für die Fliege ⋈ in Unicode ist U+22C8. Das Ergebnis eines NATURAL JOIN
s ist das Set aller Tupel-Kombinationen von R und S, welche identische Namensattribute besitzen.
Das folgende Beispiel verdeutlicht den NATURAL JOIN
anhand der Tabellen Angestellter und Abteilung:
|
|
|
Diese Definition lässt sich auch für eine Relation verwenden. Zum Beispiel ist die Verkettung von Angestellter und Abteilung der obige Join, projiziert auf alles außer das gemeinsamen Attribut AbtName. In der Kategorientheorie entspricht dies dem Faserprodukt.
Der NATURAL JOIN
ist wohl einer der wichtigsten Operatoren, da er die relationale Entsprechung des logischen AND darstellt. Erscheint die gleiche Variable in zwei Prädikaten, die mit einem AND verbunden sind, so steht diese Variable immer bei beiden für den gleichen Wert. Der NATURAL JOIN
erlaubt vor allem die Kombination von mit Fremdschlüssel assoziierten Relationen. Zum Beispiel verbindet vermutlich ein Fremdschlüssel Angestellter.AbtName mit Abteilung.AbtName und der NATURAL JOIN
von Angestellter mit Abt verbindet alle Angestellten mit ihren Abteilungen. Das funktioniert, weil der Fremdschlüssel Attribute mit dem gleichen Namen enthält. Beim gegenteiligen Beispiel des Fremdschlüssels von Abt zu Angestellter müssen vor der Verwendung des NATURAL JOIN
s diese Spalten noch einen neuen Namen erhalten. Diese Art von Join heißt EQUI JOIN
.
Die formalere Semantik des NATURAL JOIN
s ist wie folgt definiert:
- ,
dabei ist ein Prädikat, welches wahr ist, und zwar dann und nur dann, wenn r eine Funktion ist. Für gewöhnlich müssen dafür R und S mindestens ein gemeinsames Attribut besitzen, ansonsten entspricht der NATURAL JOIN
dem kartesischen Produkt.
Die Codd-Funktionen können den NATURAL JOIN
konstruieren:
Seien c1, …, cm die gemeinsamen Attributsnamen von R und S, r1, …, rn seien die einzigarten Attributsnamen für R und seien s1, …, sk die einzigartigen Attributsnamen für S. Außerdem seien die Attributsnamen x1, …, xm weder in R noch in S enthalten. Im ersten Schritt erhalten die Attribute in S einen neuen Namen:
Anschließend wenden wir das kartesische Produkt an und wählen die zu joinenden Tupel aus:
Ein NATURAL JOIN
ist eine besondere Form des EQUI JOIN
s bei dem das Join-Prädikat implizit durch einen Vergleich aller Tabellen entsteht, die den jeweils gleichen Spalten-Namen in den zu joinenden Tabellen aufweisen. Die entstehende gejointe Tabelle besteht aus lediglich einer Spalte für jedes Paar gleichnamiger Spalten. Existieren keine Spalten mit gleichem Namen, ist das Ergebnis ein CROSS JOIN
.
Die meisten Experten halten NATURAL JOIN
s für gefährlich und raten stark von ihrer Verwendung ab.[6]
Die Gefahr besteht darin, versehentlich eine neue Spalte hinzuzufügen, welche den gleichen Namen trägt wie eine Spalte in einer anderen Tabelle. Ein NATURAL JOIN
könnte diese neue Spalte dann für Vergleiche verwenden, die zu Vergleichen/Übereinstimmungen führen, welche unterschiedliche Bedingungen (für andere Spalten) als vorher benutzen.
Eine solche Abfrage könnte daher verschiedene Ergebnisse erzeugen, auch wenn die Informationen in den Tabellen sich nicht geändert, sondern nur erweitert haben.
Die Verwendung von Spalten-Namen, um automatisch Tabellen-Verknüpfungen zu bestimmen, ist bei großen Datenbanken mit hunderten oder tausenden von Tabellen keine Option, da dies eine unrealistische Beschränkung auf die Namenskonvention zur Folge hätte. Tatsächlich existierende Datenbanken sind für gewöhnlich mit Fremdschlüssel-Daten erstellt, welche aufgrund von Geschäftsregeln und Kontext nicht konsequent beschrieben sind (NULL-Werte sind erlaubt).
Dabei ist es übliche Praxis, Spalten-Namen ähnlicher Datensätze in verschiedenen Tabellen umzubenennen, und der Verlust starrer Konsistenz verbannt den NATURAL JOIN
zurück in die theoretische Diskussion.
Eine andere Notation für die obige Beispiel-Abfrage eines INNER JOIN
s mit Hilfe eines NATURAL JOIN
s lautet:
SELECT *
FROM Angestellter NATURAL JOIN Abteilung;
Durch die explizite USING
-Bedingung taucht nur eine Spalte AbteilungID ohne weiteres Attribut in der gejointen Tabelle auf:
AbteilungID | Angestellter.Nachname | Abteilung.AbteilungName |
---|---|---|
34 | Weber | Büro |
33 | Schmidt | Technik |
34 | Fischer | Büro |
33 | Schneider | Technik |
31 | Müller | Verkauf |
PostgreSQL, MySQL und Oracle unterstützen NATURAL JOIN
s, Microsoft T-SQL und IBM DB2 jedoch nicht.
Die im Join verwendeten Spalten sind implizit, weswegen der Join-Code die erwarteten Spalten nicht anzeigt und eine Veränderung der Spalten-Namen die Ergebnisse verändern kann. Im SQL:2011-Standard sind NATURAL JOIN
s Teil des optionalen F401-Pakets Extended joined table (zu Deutsch: erweiterte Join-Tabelle).
In vielen Datenbankumgebungen sind die Spalten-Namen durch den Verkäufer bestimmt und nicht durch den Abfrageentwickler. Ein NATURAL JOIN
nimmt Stabilität und Konsistenz in Spalten-Namen an, was sich durch von Verkäufern festgelegte Versionsupgrades ändern kann.
OUTER JOIN
Die gejointe Tabelle enthält jede Zeile, selbst wenn diese keine Paare bildet. Je nachdem welche Zeilen der Tabellen erhalten bleiben, ist ein OUTER JOIN
s ein LEFT OUTER
-Join, RIGHT OUTER
-Joins oder ein FULL OUTER
-Join. Die Ausdrücke LEFT, RIGHT and FULL stehen für die rechte, linke oder beide Seite(n) des JOIN
-Schlüsselworts.
Im SQL-Standard ist keine implizite Join-Notation für OUTER JOIN
s vorgesehen.
LEFT OUTER JOIN

LEFT JOIN
zweier Tabellen A und B.Das Ergebnis eines LEFT OUTER JOIN
s (oder vereinfacht LEFT JOIN
) der Tabellen A und B enthält alle Zeilen der linken ("LEFT") Tabelle A, selbst wenn die Join-Bedingung auf keine Spalte der rechten ("RIGHT") Tabelle B zutrifft.
Falls die ON
-Bedingung für eine vorgegebene Zeile der Spalte A keine Zeile für die Tabelle B liefert, generiert der Join trotzdem die Zeile der Spalte A. Die entsprechenden Einträge für die Spalten der Tabelle B sind jedoch mit dem NULL-Wert ausgegeben.
Ein LEFT OUTER JOIN
gibt alle Werte eines INNER JOIN
s wieder zusätzlich aller Werte einer LEFT-Tabelle, welche nicht der RIGHT-Tabelle entsprechen und alle Zeilen mit NULL-Werten (also leeren Werten) der linken Spalte.
Wir können nun die Abteilung eines jeden Angestellten finden und trotzdem diejenigen Angestellten auflisten, welche noch keiner Abteilung zugewiesen worden sind (im Gegensatz zum INNER JOIN
-Beispiel vorher, bei dem diese Angestellten ausgeschlossen wurden.)
Beispiel eines LEFT OUTER JOIN
s (das OUTER
-Schlüsselwort ist optional) mit der zusätzlichen kursiv geschriebenen Zeile (verglichen mit dem INNER JOIN
):
SELECT *
FROM Angestellter
LEFT OUTER JOIN Abteilung ON Angestellter.AbteilungID = Abteilung.AbteilungID;
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName | Abteilung.AbteilungID |
---|---|---|---|
Schmidt | 33 | Technik | 33 |
Müller | 31 | Verkauf | 31 |
Fischer | 34 | Büro | 34 |
Weber | 34 | Büro | 34 |
Meyer | NULL | NULL | NULL |
Schneider | 33 | Technik | 33 |
Alternative Syntax: Oracle unterstützt die veraltete Syntax.[7]
SELECT *
FROM Angestellter, Abteilung
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID(+);
Sybase unterstützt die folgende Syntax (Microsoft SQL Server unterstützt diese Version seit 2000 nicht mehr):
SELECT *
FROM Angestellter, Abteilung
WHERE Angestellter.AbteilungID *= Abteilung.AbteilungID;
IBM Informix unterstützt diese Syntax:
SELECT *
FROM Angestellter, OUTER Abteilung
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID;
RIGHT OUTER JOIN

RIGHT JOIN
zweier Tabellen A and B.Ein RIGHT OUTER JOIN
(auch RIGHT JOIN
) ähnelt stark einem LEFT OUTER JOIN
mit umgekehrter Abarbeitung der Tabellenreihenfolge. Jede Zeile der rechten ("RIGHT") Tabelle B kommt in der gejointen Tabelle mindestens einmal vor. Im Falle keiner passenden Zeile der linken ("LEFT") Tabelle A erscheint der NULL-Wert in den Spalten von A für die Zeilen, welche keine Entsprechung in B haben.
Ein RIGHT OUTER JOIN
gibt alle Werte der rechten ("RIGHT") Tabelle und passenden Werte der linken ("LEFT") Tabelle wieder (im Falle keiner passendenen Join-Prädikate NULL). Daher können wir zum Beispiel jeden Angestellten und seine Abteilung finden, aber dennoch Abteilungen anzeigen lassen, die keine Angestellten besitzen.
Weiter unten ist ein Beispiel eines RIGHT OUTER JOIN
s (das OUTER
-Schlüsselwort ist optional) mit der Ergebniszeile in kursiver Schrift:
SELECT *
FROM Angestellter RIGHT OUTER JOIN Abteilung
ON Angestellter.AbteilungID = Abteilung.AbteilungID;
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName | Abteilung.AbteilungID |
---|---|---|---|
Weber | 34 | Büro | 34 |
Schmidt | 33 | Technik | 33 |
Fischer | 34 | Büro | 34 |
Schneider | 33 | Technik | 33 |
Müller | 31 | Verkauf | 31 |
NULL | NULL | Marketing | 35 |
RIGHT
und LEFT OUTER JOIN
sind funktional äquivalent. Keiner von beidem besitzt eine Funktionalität, welche der andere nicht hat. Sie können sich also durch eine Vertauschung der Tabellenreihenfolge gegenseitig ersetzen.
FULL OUTER JOIN

FULL JOIN
zweier Tabellen A and B.Ein FULL OUTER JOIN
verbindet die Resultate eines LEFT
und eines RIGHT OUTER JOIN
s. Nicht passende Zeileneinträge eines FULL OUTER JOIN
s erhalten NULL-Werte für jede Spalte der Tabelle, denen eine passende Zeile fehlt. Passende Zeilen erzeugen eine einzelne Zeile im Ergebnis-Set, welche die Spalten beider Tabellen erhält.
Zum Beispiel können wir dadurch jeden Angestellten anzeigen, der einer Abteilung zugewiesen ist, und jede Abteilung, die einen Angestellten hat, aber zusätzlich auch Angestellte, die nicht Teil einer Abteilung sind, oder Abteilungen, die keine Angestellten haben.
Beispiel für einen FULL OUTER JOIN
(das OUTER
-Schlüsselwort ist optional):
SELECT *
FROM Angestellter FULL OUTER JOIN Abteilung
ON Angestellter.AbteilungID = Abteilung.AbteilungID;
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName | Abteilung.AbteilungID |
---|---|---|---|
Weber | 34 | Büro | 34 |
Schmidt | 33 | Technik | 33 |
Fischer | 34 | Büro | 34 |
Meyer | NULL | NULL | NULL |
Schneider | 33 | Technik | 33 |
Müller | 31 | Verkauf | 31 |
NULL | NULL | Marketing | 35 |
Manche Datenbanksysteme unterstützen die Funktionalität des FULL OUTER JOIN
s nicht direkt. Sie können diesen aber durch den Gebrauch eines INNER JOIN
s und eines UNION ALL
imitieren, indem sie die alleinstehenden Zeilen der rechten ("RIGHT") und der linken ("LEFT") Tabelle sowie den INNER JOIN
mit einem UNION ALL
verbinden.
Das gleiche Beispiel sieht dann wie folgt aus:
SELECT Angestellter.Nachname, Angestellter.AbteilungID,
Abteilung.AbteilungName, Abteilung.AbteilungID
FROM Angestellter
INNER JOIN Abteilung ON Angestellter.AbteilungID = Abteilung.AbteilungID
UNION ALL
SELECT Angestellter.Nachname, Angestellter.AbteilungID,
cast(NULL as varchar(20)), cast(NULL as integer)
FROM Angestellter
WHERE NOT EXISTS (
SELECT * FROM Abteilung
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID)
UNION ALL
SELECT cast(NULL as varchar(20)), cast(NULL as integer),
Abteilung.AbteilungName, Abteilung.AbteilungID
FROM Abteilung
WHERE NOT EXISTS (
SELECT * FROM Angestellter
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID)
Alternativen
Ein UNION ALL
zwischen einem INNER JOIN
und einem SELECT
der Zeilen der Haupttabelle, welche nicht die Join-Bedingung erfüllen, erzielt das gleiche Ergebnis wie ein OUTER JOIN
.
Zum Beispiel ist
SELECT Angestellter.Nachname, Angestellter.AbteilungID, Abteilung.AbteilungName
FROM Angestellter
LEFT OUTER JOIN Abteilung ON Angestellter.AbteilungID = Abteilung.AbteilungID;
eine äquivalente Notation zu:
SELECT Angestellter.Nachname, Angestellter.AbteilungID, Abteilung.AbteilungName
FROM Angestellter
INNER JOIN Abteilung ON Angestellter.AbteilungID = Abteilung.AbteilungID
UNION ALL
SELECT Angestellter.Nachname, Angestellter.AbteilungID, cast(NULL as varchar(20))
FROM Angestellter
WHERE NOT EXISTS (
SELECT * FROM Abteilung
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID)
SELF JOIN
Ein SELF JOIN
ist ein Join einer Tabelle auf sich selbst.[8]
Im Falle zweier separater Tabellen für die Angestellten und einer Abfrage nach dem gleichen Land beider Tabellen könnte zum Beispiel eine gewöhnliche Join-Operation die Antwort-Tabelle ausgeben. Sehr oft finden sich jedoch alle Informationen innerhalb einer einzigen großen Tabelle.[9]
Die folgende Angestellter
-Tabelle sei gegeben:
AngestellterID | Nachname | Land | AbteilungID |
---|---|---|---|
123 | Müller | Australien | 31 |
124 | Schmidt | Australien | 33 |
145 | Schneider | Australien | 33 |
201 | Fischer | Amerika | 34 |
305 | Weber | Deutschland | 34 |
306 | Meyer | Deutschland | NULL |
Eine mögliche Abfrage wäre:
SELECT F.AngestellterID, F.Nachname, S.AngestellterID, S.Nachname, F.Land
FROM Angestellter F INNER JOIN Angestellter S ON F.Land = S.Land
WHERE F.AngestellterID < S.AngestellterID
ORDER BY F.AngestellterID, S.AngestellterID;
Dies würde folgende Tabelle als Resultat ergeben:
AngestellterID | Nachname | AngestellterID | Nachname | Land |
---|---|---|---|---|
123 | Müller | 124 | Schmidt | Australien |
123 | Müller | 145 | Schneider | Australien |
124 | Schmidt | 145 | Schneider | Australien |
305 | Weber | 306 | Meyer | Deutschland |
Zu diesem Beispiel:
F
undS
sind Aliase für die erste und zweite Kopie der Angestellter-Tabelle.- Die Bedingung
F.Land = S.Land
schließt die Paarbildung von Angestellten verschiedener Länder aus. Die obige Fragestellung suchte nach Angestellten im gleichen Land. - Die Bedingung
F.AngestellterID < S.AngestellterID
schließt die Paarbildungen derAngestellterID
s der ersten Angestellter-Tabelle aus, die größer oder gleich derAngestellterID
der zweiten Tabelle sind. In anderen Worten: die Folge dieser Bedingung ist das Ausschließen duplizierter Paarbildungen und Selbst-Paarbildungen. Ohne sie generiert sich die folgende wenig nützliche Tabelle (nur der Ausschnitt mit Deutschland ist gezeigt):
AngestellterID | Nachname | AngestellterID | Nachname | Land |
---|---|---|---|---|
305 | Weber | 305 | Weber | Deutschland |
305 | Weber | 306 | Meyer | Deutschland |
306 | Meyer | 305 | Weber | Deutschland |
306 | Meyer | 306 | Meyer | Deutschland |
Lediglich eine der beiden mittleren Paarbildungen ist nötig, um der Fragestellung zu genügen: die oberste und unterste sind für dieses Beispiel nicht von Interesse.
Einbindung
Datenbanksystemen erfordern viel Arbeit bei der effizienten Einbindung von Joins, da relationale Systeme für gewöhnlich die Verwendung von Joins mit sich bringen. Die Schwierigkeit liegt in der Optimierung ihrer effizienten Ausführung. Das Problem entsteht, da INNER JOIN
s sich sowohl kommutativ als auch assoziativ verhalten. In der Praxis muss der Benutzer dadurch nur noch die Liste mit den zu joinenden Tabellen und die zu verwendende Join-Bedingung ausgeben. Das Datenbanksystem übernimmt anschließend die Aufgabe, den effizientesten Weg für die Durchführung zu bestimmen. Ein Abfrageoptimierer bestimmt dabei die Ausführungsart von Abfragen in Joins.
Ein Abfrageoptimierer hat zwei elementare Freiheiten:
- Join-Reihenfolge: Aufgrund der kommutativen und assoziativen Eigenschaft der Join-Funktionen verändert die Abarbeitung der Reihenfolge, in der das System die Join-Tabellen abarbeitet, nicht das Ergebnis. Die Wahl einer geeigneten Join-Reihenfolge reduziert die eventuell sehr hohen Kosten einer Join-Durchführung.
- Join-Methode: Bei zwei gegebenen Tabellen und einer Join-Bedingung können verschiedene Algorithmen das Ergebnis-Set eines Joins produzieren. Welcher Algorithmus am effizientesten läuft, hängt von der Größe der eingegebenen Tabellen, der Anzahl der Zeilen jeder Tabelle, die zur Join-Bedingung passen, und von den Arbeitsschritten der restlichen Abfrage ab.
Die Abarbeitung durch die Joinalgorithmen läuft dabei unterschiedlich ab. Die Eingaben eines Joins heißen äußere ("outer") oder innere ("inner") Operatoren, beziehungsweise links ("LEFT") und rechts ("RIGHT"). Bei verschachtelten Schleifen zum Beispiel scannt das Datenbanksystem die ganze innere Relation für jede Zeile der äußeren Relation.
Klassische Auswertungspläne die Joins enthalten:[10]
- links-tief ("left-deep"): eine Basistabelle als innerer Operator für jeden Join des Auswertungsplans
- rechts-tief ("right-deep"): eine Basistabelle als äußerer Operator für jeden Join des Auswertungsplans
- bushy: weder links-tief noch rechts-tief, beide Join-Eingaben können selbst aus Joins entstehen
Die Namen leiten sich aus dem Erscheinungsbild des als Baum gezeichneten Auswertungsplans ab. Dabei ist durch Namenskonvention die äußere Relation als linke ("LEFT") Seite und die innere Relation als rechte ("RIGHT") Seite definiert.
Join-Algorithmen
Die drei fundamentalen Algorithmen für Join-Operation lauten: Nested Loop-Join, Sort-Merge Join und Hash-Join.
Join-Indizes
Join-Indizes sind Datenbankindizes, die das Verarbeiten von Join-Abfragen in Data-Warehouses ermöglichen: Sie sind seit 2012 in Oracle[11] und Teradata eingebunden.
Die Definition der Teradata-Einbindung für ausgewiesene Spalten, aggregierte Funktionen von Spalten oder Komponenten von Datenspalten einer oder mehrerer Tabellen ähnelt der Syntax einer View: Ein einzelner Join-Index erlaubt die Definition von bis zu 64 Spalten(ausdrücken). Optional mit einer Definition der Spalte des Primärschlüssels der erstellen Daten: Parallel arbeitende Hardware verwendet die Spaltenwerte für die Partition der Inhalte der Indizes über mehrere Platten. Bei interaktiven Benutzerupdates von Quelldaten updaten sich die Join-Indizes automatisch mit. Jegliche Abfrage, deren Where-Bedingung auf eine Kombination von Spalten oder Spaltenausdrücken, die im Join-Index definiert sind („Covering-Abfrage“), eingeht, führt zu einem Auslesen des Join-Indexes statt der Original-Tabellen und deren Indizes während der Ausführung.
Die Einbindung von Oracle beschränkt sich selbst durch die Verwendung des Bitmap-Indexes. Dieser indiziert und verbindet zusammengehörige niedrig-kardinale Spalten (weniger als 300 einzigartige Werten gemäß Oracle-Dokumentation). Das Beispiel von Oracle verwendet ein Bestandsverzeichnis, für welches verschiedene Zulieferer unterschiedliche Teile liefern. Das betreffende Schema hat drei verlinkte Tabellen: zwei „Master-Tabellen“ Teil ("Part") und Zulieferer ("Supplier") und eine „Detail-Tabelle“ Inventar ("Inventory"). Das letzte ist eine many-to-many-Tabelle, welche Zulieferer und Teil miteinander verbindet und die meisten Zeilen enthält. Jedes Teil hat einen Teil-Typ, jeder Zulieferer hat seinen Sitz in den USA und eine Spalte Staat ("State"). Die USA bestehen aus nicht mehr als 60 Staaten und Territorien und die Teil-Typen sind auf 300 beschränkt. Ein Join der obigen drei Tabellen definiert in der Regel den Bitmap-Join-Index und spezifiziert den Teil-Typ und den Zulieferer-Staat-Index. Er ist jedoch durch die Inventar-Tabelle definiert, selbst wenn die Spalten Teil-Typ und Zulieferer-Staat nur von Zulieferer, beziehungsweise Teil "geliehen" sind.
Genauso wie für Teradata, verwendet Oracle ein Bitmap-Join-Index nur um eine Abfrage zu beantworten, dessen Where-Bedingung auf Spalten beschränkt ist, die im Join-Index enthalten sind.
STRAIGHT_JOIN
In manchen Datenbank-Systemen kann der Benutzer das Lesen der Tabellen eines Joins in einer bestimmten Reihenfolge erzwingen. Dies ist besonders hilfreich, wenn der Abfrageoptimierer die Tabellen in einer ineffizienten Reihenfolge abarbeitet. Der Befehl STRAIGHT_JOIN
in MySQL beispielsweise liest die Tabellen in exakt der gleichen Reihenfolge der Abfrageliste.[12]
Siehe auch
Literatur
- Phillip J Pratt: A Guide To SQL, Seventh Edition. Thomson Course Technology, 2005, ISBN 978-0-619-21674-0.
- Nilesh Shah: Database Systems Using Oracle – A Simplified Guide to SQL and PL/SQL Second Edition. International Auflage. Pearson Education International, 2005, ISBN 0-13-191180-5 ( [2002]).
- Clement T. Yu, Weiyi Meng: Principles of Database Query Processing for Advanced Applications. Morgan Kaufmann, 1998, ISBN 978-1-55860-434-6 (google.com [abgerufen am 3. März 2009]).
Weblinks
- Speziell zu Produkten
Einzelnachweise
- ↑ SQLGuides: SQL CROSS JOIN. Abgerufen am 19. September 2018.
- ↑ Greg Robidoux: Avoid SQL Server functions in the WHERE Bedingung for Performance. In: MSSQL Tips, 5/3/2007
- ↑ Patrick Wolf: Caution when using PL/SQL functions in a SQL statement. Inside Oracle APEX, 11/30/2006
- ↑ Gregory A. Larsen: T-SQL Best Practices – Don’t Use Scalar Value Functions in Column List or WHERE Bedingungs. 10/29/2009,
- ↑ Java2s: Simplifying Joins with the USING Keyword. Abgerufen am 19. September 2018.
- ↑ AskTom: Oracle support of ANSI joins. Abgerufen am 18. September 2018.
- ↑ DBA Oracle: Left Outer Join. Abgerufen am 19. September 2018.
- ↑ Nilesh Shah: Database Systems Using Oracle – A Simplified Guide to SQL and PL/SQL. Second Edition (International ed.). Pearson Education International, (2005) [2002], S. 165
- ↑ Entnommen aus: Phillip J. Pratt: A Guide To SQL. Seventh Edition. Thomson Course Technology, 2005, S. 115–116
- ↑ Clement T. Yu, Weiyi Meng: Principles of Database Query Processing for Advanced Applications. 1998, S. 213
- ↑ DBA Oracle: Oracle Bitmap Join Index. Abgerufen am 19. September 2018.
- ↑ Oracle Corporation: MySQL 5.7 Reference Manual:JOIN Syntax. Abgerufen am 19. September 2018.