Ein SQL-Join verknüpft eine ode mehrere Spalten einer Relationalen Datenbank. Das Ergebnis kann als Tabelle ausgegeben oder weiterverarbeitet werden. Ein JOIN
ermöglicht das Verknüpfen von Spalten einer einzelnen Tabelle (self-Tabelle) oder mehrere Tabellen welche identische Werte aufweisen. 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 joined Tabelle) ein Join auf sich selbst durchführen (SELF JOIN
).
Ein Programmierer deklariert ein JOIN
-Statement um mögliche Reihen für einen Join zu identifizieren. Falls das ermittelte Prädikat wahr ist, wird die verknüpfte Spalte in einem entsprechenden Format, einem Satz von Reihen oder einer temporären Tabelle wiedergegeben.
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. Zum kann zum Beispiel eine Abteilung mit mehreren Angestellten verknüpft sein. Ein Join dieser beiden Tabellen 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 von Joins verwenden die beiden weiter unten dargestellten Tabellen. Die Reihen dieser Tabellen dienen der Beschreibung der Wirkweise verschiedener Arten von Joins und deren Prädikate.
In den folgenden Tabellen ist die Spalte AbteilungID
der Tabelle Abteilung
(welche als Abteilung.AbteilungID
bezeichnet werden kann) der Primärschlüssel, während Angestellter.AbteilungID
der Fremdschlüssel ist.
Nachname | AbteilungID |
---|---|
Müller | 31 |
Schmidt | 33 |
Schneider | 33 |
Fischer | 34 |
Weber | 34 |
Meyer | NULL |
AbteilungID | AbteilungName |
---|---|
31 | Verkauf |
33 | Technik |
34 | Buero |
35 | Marketing |
Anmerkung: In der obigen Tabelle Angestellter wurde dem Angestellten "Meyer" noch keine Abteilung zugewiesen. Außerdem, sollte beachtet werden, dass bisher kein Angestellter der Abteilung "Marketing" zugewiesen worden ist.
Dies ist das SQL-Statement um die zuvor genannten Tabellen zu erzeugen.
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, 'Buero');
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 Kartesisches Produkt der Tabellenreihen eines Joins wieder. Mit anderen Worten, ein Join erstellt Reihen welche jede Reihe der einen Tabelle mit jeder Reihe der anderen Tabelle verknüpft. [1]
Beispiel eines expliziten CROSS JOIN
s:
SELECT *
FROM Angestellter <code>CROSS JOIN</code> 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 | Buero | 34 |
Schmidt | 33 | Buero | 34 |
Schneider | 33 | Buero | 34 |
Weber | 34 | Buero | 34 |
Fischer | 34 | Buero | 34 |
Meyer | NULL | Buero | 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 Reihen der gejointen Tabelle zu filtern. Das Resultat eines CROSS JOIN
s kann durch eine WHERE
-Clause gefiltert werden, was wiederum einem INNER JOIN
entsprechen kann.
Im SQL:2011-Standard werden CROSS JOIN
s als Teil des optionalen F401-Pakets "Extended joined table" aufgelistet.
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 gejointen Tabellen übereinstimmende Spalten-Werte vorhanden sein. Diese Join-Operation wird in Software sehr oft verwendet, sollte aber nicht als beste Lösung für alle Problemstellungen gesehen werden. 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 vebindet. Die Abfrage vergeleicht jede Zeile von Tabelle A mit jeder Zeile von Tabelle B um alle Paare zu finden, die dem Join-Prädikat genügen. Falls das Join-Prädikat keine NULL-Werte findet, werden die Spalten-Werte jedes übereinstimmenden Zeilenpaars von A und B in eine Ergebnis-Zeile vereinigt.
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 anschließender Ausgabe aller Zeilen welche dem Join-Prädikat genügen.
Gegenwärtige SQL-Umsetzungen verwenden für gewöhnlich Ansätze, wie z.B.: Hash Joins oder Sort-Merge Joins, da das Berechnen eines kartesischen Produkts viel langsamer wäre und viel Arbeitsspeicher benötigen würde.
SQL kennt zwei verschiedene syntaktische Werte Joins zu verwenden: die "explizite Join-Notation" und die "implizite Join-Notation". Die "implizite Join-Notation" wird nicht mehr als Best practice angesehen, wird jedoch von Datenbanksystemen weiterhin unterstützt.
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 defnieren.
Beispiel für die explizite Join-Notation:
SELECT Angestellter.Nachname, Angestellter.AbteilungID, Abteilung.AbteilungName
FROM Angestellter
INNER JOIN Abteilung ON
Angestellter.AbteilungID = Abteilung.AbteilungID
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName |
---|---|---|
Fischer | 34 | Buero |
Schmidt | 33 | Technik |
Weber | 34 | Buero |
Schneider | 33 | Technik |
Müller | 31 | Verkauf |
In der "impliziten" Join-Notation werden die zu joinenden Tabellen in der FROM
-Clause der SELECT
-Abfrage , lediglich durch ein Komma getrennt, genannt. Dadurch wird ein CROSS JOIN
durchgeführt und auf die WHERE
-Clause kann weitere Filter-Prädikate angewandt werden, welche vergleichbar zu den Join-Prädikaten der expliziten Join-Notation funktionieren.
Das folgende Beispiel ist äquivalent zum vorherigen, dieses Mal wird jedoch die implizite Join-Notation verwendet:
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. In den Fällen in denen AbteilungID dieser Tabellen passen (also das Join-Prädikat erfüllt ist) wird die Abfrage die Spalten Nachname, AbteilungID und AbteilungName der beiden Tabellen zu einer Ergebnis-Zeile verbinden. Sollte AbteilungID nicht passen, wird keine Ergebnis-Zeile generiert. Das Ergebnis des Auswertungsplans der Abfrage sieht folgendermaßen aus:
Angestellter.Nachname | Angestellter.AbteilungID | Abteilung.AbteilungName | Abteilung.AbteilungID |
---|---|---|---|
Fischer | 34 | Buero | 34 |
Schmidt | 33 | Technik | 33 |
Weber | 34 | Buero | 34 |
Schneider | 33 | Technik | 33 |
Müller | 31 | Verkauf | 31 |
Der Angestelle "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, kann dieses Verhalten als simpler Bug gesehen werden, welcher durch das Ersetzen von INNER JOIN
durch
OUTER JOIN
, gefixt werden kann.
Bei einem Join zweier Tabellen, welche NULL-Werte enthalten, ist besondere Vorsicht angebracht. In diesem Fall wird kein NULL-Wert mit einem anderen Wert übereinstimmen (auch nicht mit dem NULL-Wert selbst). Diese Einträge können jedoch durch die explizite Verwendung eines modifizierten Prädikats in der Join-Bedingung berücksichtigt werden. Dabei wird zunächst überprüft, ob die Join-Spalten den Wert NOT NULL
aufweisen, bevor die restlichen Prädikatsbedingungen angewandt werden.
Der INNER JOIN
kann nur bedenkenlos in Datenbanken verwendet werden, welche Referentielle Integrität erzwingen oder in Fällen in denen die Join-Spalten mit Sicherheit nicht NULL sind.
Viele transaktionsverarbeitende relationale Datenbanken basieren auf dem ACID-Prinzip-Standards für Datenupdates um die Datenintegrität zu gewährleisten wodurch INNER JOIN
s eine gute Wahl sind. Transaktionsdatenbanken haben jedoch meist erwünschte Join-Spalten, die NULL-Werte enthalten können. Manche report-erstellende relationale Datenbanken und Data-Warehouses verwenden Batch-Updates für ETL-Prozesse, welche den Zwang zur Erhaltung der referentiellen 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 Design der Datenbank und den Besonderheiten der Datensätze ab. Ein LEFT OUTER JOIN
kann für gewöhnlich durch einen INNER JOIN
ersetzt werden, sofern die Join-Spalten in einer Tabelle NULL-Werte enthalten.
Spalten mit Datensätzen die NULL-Werte enthalten sollten nie als Verknüpfung in einem INNER JOIN
verwendet werden, außer Spalten mit NULL-Werten sollen entfernt werden. In diesem Fall kann ein INNER JOIN
sogar schneller als ein OUTER JOIN
sein, da der Join und das Filtern in einem einzigen Schritt abgearbeitet werden.
Anderseits kann ein INNER JOIN
verheerend langsame Performance oder sogar einen Serverabsturz zur Folge haben, falls dieser in einer hochvolumigen Abfrage in Kombination mit Datenbankfunktionen in einer WHERE-Bedingung ausgeführt wird.[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 die Anzahl der Zeilen durch den Filter, welcher von einem vorher berechneten Wert abhängt, reduziert werden können. Dies führt schließlich zu einer relativ ineffizienten Prozessverarbeitung.
Sollte ein Ergebnis-Set durch einen Join mehrerer Tabellen produziert werden, welche Master-Tabellen enthalten, die verwendet werden um ganze Text-Beschreibungen numerischer Kennzahlen nachzuschlagen ( Lookup-Tabelle), kann ein NULL-Wert in einem der Sekundärschlüssel eine Löschung der gesamten Zeile aus dem Ergebnis-Set verursachen ohne dass ein Hinweis auf einen Fehler angezeigt wird.
Eine komplexe SQL-Abfrage, welche 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 welche 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.
Ein INNER JOIN
s kann außerdem als EQUI JOIN
, als NATURAL JOIN
oder als CROSS JOIN
klassifiziert werden.
EQUI JOIN
Ein
ist ein vergleichsbasierter Join, welcher nur den Gleichheits-Vergleich im Join-Prädikat verwendet. Werden andere Vergleichsoperatoren (wie z.B.: EQUI JOIN
<
) verwendet, handelt es sich nicht um einen
. Die obige Abfrage enthält bereits ein Beispiel für einen EQUI JOIN
:
EQUI JOIN
SELECT *
FROM Angestellter JOIN Abteilung
ON Angestellter.AbteilungID = Abteilung.AbteilungID;
Der
kann wie folgt geschrieben werden:
EQUI JOIN
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 <code>INNER JOIN</code> 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 in der USING
-Liste enthaltenen Spalten werden mit einem unbestimmten Namen statt je einem für jede Tabelle des Joins angezeigt. Das obige Beispiel ergibt eine einzelne Spalte AbteilungID
und keine Angestellter.AbteilungID
- oder Abteilung.AbteilungID
-Spalte.
Die USING
-Clause wird nicht von MS SQL Server und Sybase unterstützt.
NATURAL JOIN
Der NATURAL JOIN
ist ein Spezialfall des EQUI JOIN
s. Der NATURAL JOIN
(⋈)ist eine Zweistellige Relation, welche in der Form R ⋈ S (mit R und S als Relationen) geschrieben werden kann. In Unicode wird die Fliege ⋈ mit dem Zahlencode U+22C8 dargestellt. 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:
|
|
|
This can also be used to define Relations-Verknüpfung. For example, the composition of Angestellter and Abteilung is their join as shown above, projected on all but the common attribute AbtName. In Kategorientheorie, the join is precisely the Faserprodukt.
The NATURAL JOIN
is arguably one of the most important operators since it is the relational counterpart of logical AND. Note that if the same variable appears in each of two predicates that are connected by AND, then that variable stands for the same thing and both appearances must always be substituted by the same value. In particular, the NATURAL JOIN
allows the combination of relations that are associated by a Fremdschlüssel. For example, in the above example a foreign key probably holds from Angestellter.AbtName to Abteilung.AbtName and then the NATURAL JOIN
of Angestellter and Abt combines all Angestellters with their Abteilungs. This works because the foreign key holds between attributes with the same name. If this is not the case such as in the foreign key from Abt.manager to Angestellter.Name then these columns have to be renamed before the NATURAL JOIN
is taken. Such a join is sometimes also referred to as an EQUI JOIN
.
More formally the semantics of the NATURAL JOIN
are defined as follows:
- ,
where Fun is a Prädikat that is true for a Relation r If and only if r is a function. It is usually required that R and S must have at least one common attribute, but if this constraint is omitted, and R and S have no common attributes, then the NATURAL JOIN
becomes exactly the Cartesian product.
The NATURAL JOIN
can be simulated with Codd's primitives as follows. Let c1, …, cm be the attribute names common to R and S, 'r1, …, rn be the attribute names unique to R and let s1, …, sk be the attributes unique to S. Furthermore, assume that the attribute names x1, …, xm are neither in R nor in S. In a first step the common attribute names in S can now be renamed:
Then we take the Cartesian product and select the tuples that are to be joined:
A NATURAL JOIN
is a type of
where the join predicate arises implicitly by comparing all columns in both tables that have the same column-names in the joined tables. The resulting joined table contains only one column for each pair of equally named columns. In the case that no columns with the same names are found, the result is a [[#EQUI JOIN
CROSS JOIN
|CROSS JOIN
]].
Most experts agree that NATURAL JOIN
s are dangerous and therefore strongly discourage their use.[6] The danger comes from inadvertently adding a new column, named the same as another column in the other table. An existing NATURAL JOIN
might then "naturally" use the new column for comparisons, making comparisons/matches using different criteria (from different columns) than before. Thus an existing query could produce different results, even though the data in the tables have not been changed, but only augmented. The use of column names to automatically determine table links is not an option in large databases with hundreds or thousands of tables where it would place an unrealistic constraint on naming conventions. Real world databases are commonly designed with Fremdschlüssel data that is not consistently populated (NULL values are allowed), due to business rules and context. It is common practice to modify column names of similar data in different tables and this lack of rigid consistency relegates NATURAL JOIN
s to a theoretical concept for discussion.
The above sample query for INNER JOIN
s can be expressed as a NATURAL JOIN
in the following way:
SELECT *
FROM Angestellter NATURAL JOIN Abteilung;
As with the explicit USING
clause, only one AbteilungID column occurs in the joined table, with no qualifier:
AbteilungID | Angestellter.Nachname | Abteilung.AbteilungName |
---|---|---|
34 | Weber | Buero |
33 | Schmidt | Technik |
34 | Fischer | Buero |
33 | Schneider | Technik |
31 | Müller | Verkauf |
PostgreSQL, MySQL and Oracle support NATURAL JOIN
s; Microsoft T-SQL and IBM DB2 do not. The columns used in the join are implicit so the join code does not show which columns are expected, and a change in column names may change the results. In the SQL:2011 standard, NATURAL JOIN
s are part of the optional F401, "Extended joined table", package.
In many database environments the column names are controlled by an outside vendor, not the query developer. A NATURAL JOIN
assumes stability and consistency in column names which can change during vendor mandated version upgrades.
OUTER JOIN
Die gejointe Tabelle enthält jede Zeile, selbst wenn diese keine Paare bilden. OUTER JOIN
s werden außerdem in LEFT OUTER
-Joins, RIGHT OUTER
-Joins und FULL OUTER
-Joins unterteilt. Das Kriterium ist hierfür, welche Zeilen der Tabellen erhalten bleiben. 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
-Clause für eine vorgegebene Zeile der Spalte A keine Zeile für die Tabelle B liefert, wird der Join trotzdem die Zeile der Spalte A ausgeben. 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 worden.)
Beispiel eines LEFT OUTER JOIN
s (das OUTER
-Schlüsselwort ist optional) mit der zusätzlichen in 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 | Buero | 34 |
Weber | 34 | Buero | 34 |
Meyer | NULL | NULL | NULL |
Schneider | 33 | Technik | 33 |
Alternative Syntax: Oracle unterstüt die veraltete [7] Sytax.
SELECT *
FROM Angestellter, Abteilung
WHERE Angestellter.AbteilungID = Abteilung.AbteilungID(+)
Sybase unterstützt die folgende Sytax (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 dem Unterschied, dass die Tabellen in umgekehrter Reihenfolge abgearbeitet werden. Jede Zeile der rechten ("RIGHT") Tabelle (B) wird in der gejointen Tabelle mindestens einmal vorkommen. Im Falle keiner passenden Zeile der linken ("LEFT") Tabelle (A) erscheint der NULL-Wert in den Spalten von A für die Reihen 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 oder 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 | Buero | 34 |
Schmidt | 33 | Technik | 33 |
Fischer | 34 | Buero | 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 also sich gegenseitig ersetzen indem die Reihenfolge der Tabellen in der Abfrage vertauscht wird.
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 bei einem FULL OUTER JOIN
s werden mit NULL-Werten für jede Spalte der Tabelle versehen, denen eine passende Zeile fehlt. Für passende Zeilen wird eine einzelne Zeile im Ergebnis-Set erstellt, welche die Spalten beider Tabellen erhält.
Zum Beispiel können wir dadurch jeden Angestellten anzeigen, welche 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 | Buero | 34 |
Schmidt | 33 | Technik | 33 |
Fischer | 34 | Buero | 34 |
Meyer | NULL | NULL | NULL |
Schneider | 33 | Technik | 33 |
Müller | 31 | Verkauf | 31 |
NULL | NULL | Marketing | 35 |
Manche Datenbank-Systeme 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
Das Ergebnis eines OUTER JOIN
s kann auch mit einem UNION ALL
zwischen einem INNER JOIN
und einem SELECT
der Zeilen der "Haupt"-Tabelle welche nicht die Join-Bedingung erfüllen, erreicht werden.
Zum Beispiel kann
SELECT Angestellter.Nachname, Angestellter.AbteilungID, Abteilung.AbteilungName
FROM Angestellter
LEFT OUTER JOIN Abteilung ON Angestellter.AbteilungID = Abteilung.AbteilungID;
auch auf diese Weise geschrieben werden:
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]
Beispiel:
Im Falle zweier separater Tabellen für die Angestellten und einer Abfrage nach dem gleichen Land beider Tabellen, könnte eine gewöhnliche Join-Operation verwendet werden um die Antwort-Tabelle zu finden. 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 <code>INNER JOIN</code> 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 Paarbildung dererAngestellterID
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 Auschließen duplizierter Paarbildungen und Selbst-Paarbildungen. Ohne sie würde die folgende weniger nützliche Tabelle erzeugt werden (nur der Ausschnitt des Results 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 sind nötig um der Fragestellung zu genügen: die oberste und unterste sind für dieses Beispiel nicht von Interesse.
Einbindung
Much work in database-systems has aimed at efficient implementation of joins, because relational systems commonly call for joins, yet face difficulties in optimising their efficient execution. The problem arises because INNER JOIN
s operate both kommutativ and assoziativ. In practice, this means that the user merely supplies the list of tables for joining and the join conditions to use, and the database system has the task of determining the most efficient way to perform the operation. A Abfrageoptimierer determines how to execute a query containing joins. A query optimizer has two basic freedoms:
- Join order: Because it joins functions commutatively and associatively, the order in which the system joins tables does not change the final result set of the query. However, join-order could have an enormous impact on the cost of the join operation, so choosing the best join order becomes very important.
- Join method: Given two tables and a join condition, multiple Algorithmen can produce the result set of the join. Which algorithm runs most efficiently depends on the sizes of the input tables, the number of rows from each table that match the join condition, and the operations required by the rest of the query.
Many join-algorithms treat their inputs differently. One can refer to the inputs to a join as the "outer" and "inner" join operands, or "LEFT" and "RIGHT", respectively. In the case of nested loops, for example, the database system will scan the entire inner relation for each row of the outer relation.
One can classify query-plans involving joins as follows:[10]
- left-deep
- using a base table (rather than another join) as the inner operand of each join in the plan
- right-deep
- using a base table as the outer operand of each join in the plan
- bushy
- neither left-deep nor right-deep; both inputs to a join may themselves result from joins
These names derive from the appearance of the Auswertungsplan if drawn as a Baum, with the OUTER JOIN relation on the LEFT and the inner relation on the RIGHT (as convention dictates).
Join-Algorithmen
Die drei fundamentalen Algorithmen für Join-Operation lauten: Nested Loop-Join, Sort-Merge Join und Hash-Join
Join-Indizes
Join indexes are Datenbankindizes that facilitate the processing of join queries in Data-Warehouses: they are currently (2012) available in implementations by Oracle[11] and Teradata.[12]
In the Teradata implementation, specified columns, aggregate functions on columns, or components of date columns from one or more tables are specified using a syntax similar to the definition of a View : up to 64 columns/column expressions can be specified in a single join index. Optionally, a column that defines the Primärschlüssel of the composite data may also be specified: on parallel hardware, the column values are used to partition the index's contents across multiple disks. When the source tables are updated interactively by users, the contents of the join index are automatically updated. Any query whose Where-Zusatz specifies any combination of columns or column expressions that are an exact subset of those defined in a join index (a so-called "covering query") will cause the join index, rather than the original tables and their indexes, to be consulted during query execution.
The Oracle implementation limits itself to using Bitmap-Indizes. A bitmap join index is used for low-cardinality columns (i.e., columns containing fewer than 300 distinct values, according to the Oracle documentation): it combines low-cardinality columns from multiple related tables. The example Oracle uses is that of an inventory system, where different suppliers provide different parts. The schema has three linked tables: two "master tables", Part and Supplier, and a "detail table", Inventory. The last is a many-to-many table linking Supplier to Part, and contains the most rows. Every part has a Part Type, and every supplier is based in the USA, and has a State column. There are not more than 60 states+territories in the USA, and not more than 300 Part Types. The bitmap join index is defined using a standard three-table join on the three tables above, and specifying the Part_Type and Supplier_State columns for the index. However, it is defined on the Inventory table, even though the columns Part_Type and Supplier_State are "borrowed" from Supplier and Part respectively.
As for Teradata, an Oracle bitmap join index is only utilized to answer a query when the query's Where-Zusatz specifies columns limited to those that are included in the join index.
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 Join-Optimierer die Tabellen in einer ineffizienten Reihenfolge abarbeitet. In MySQL beispielsweise werden mit dem Befehl
die Tabellen in exakt der gleichen Reihenfolge gelesen, wie sie in der Abfrage aufgelistet wurden.[13]
STRAIGHT_JOIN
Siehe auch
Weiterführende 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]).
Externe Links
Einzelnachweise
- ↑ SQL
CROSS JOIN
- ↑ Greg Robidoux, "Avoid SQL Server functions in the WHERE clause for Performance", MSSQL Tips, 5/3/2007
- ↑ Patrick Wolf, "Inside Oracle APEX "Caution when using PL/SQL functions in a SQL statement", 11/30/2006
- ↑ Gregory A. Larsen, "T-SQL Best Practices - Don't Use Scalar Value Functions in Column List or WHERE Clauses", 10/29/2009,
- ↑ Simplifying Joins with the USING Keyword
- ↑ Ask Tom "Oracle support of ANSI joins."
INNER JOIN
s/#comment-2837 Back to basics:INNER JOIN
s » Eddie Awad's Blog - ↑ Oracle
LEFT OUTER JOIN
- ↑ Shah, Nilesh (2005) [2002], Database Systems Using Oracle – A Simplified Guide to SQL and PL/SQL Second Edition (International ed.), Pearson Education International,S. 165
- ↑ Entnommen aus Pratt, Phillip J (2005), A Guide To SQL, Seventh Edition, Thomson Course Technology,S. 115– 116
- ↑ Yu, Clement T.; Meng, Weiyi (1998),| Principles of Database Query Processing for Advanced Applications S.213
- ↑ Oracle Bitmap Join Index. URL: http://www.dba-oracle.com/art_builder_bitmap_join_idx.htm
- ↑ Teradata Join Indexes. Archived copy. Archiviert vom am 16. Dezember 2012; abgerufen am 14. Juni 2012.
- ↑ 13.2.9.2 JOIN Syntax. In: MySQL 5.7 Reference Manual. Oracle Corporation, abgerufen am 3. Dezember 2015.