Kurz-Einleitung zu SQL-Joins
SQL-Joins dienen der Verknüpfung von Datenbanktabellen. Sie sind ein unverzichtbares Werkzeug für Datenbank-Entwickler, sowohl on-premise, als auch mit Azure SQL. Doch auch Controller sollten SQL-Joins kennen, um das meiste aus ihren Daten rauszuholen. In diesem Beitrag, der sich an SQL-Einsteiger richtet, beschreiben wir die geläufigsten Join-Typen anhand einfacher Beispiele: Inner Join, Left/Right Outer Join und Full Outer Join.
Um SQL-Joins effizient nutzen zu können, ist es notwendig, den schematischen Aufbau der Datenbank zu kennen. Das gängigste Modell ist dabei das Sternschema. Hier hat man eine zentrale Faktentabelle, in der zum Beispiel Transaktionen gelistet sind, sowie mehrere Dimensionstabellen mit weiterführenden Informationen. Diese können beispielsweise Kundendaten enthalten oder Informationen zu den verkauften Artikeln.
Die einzelnen Kunden und Artikel werden in der jeweiligen Dimension mit eindeutigen numerischen Kennnummern versehen, dem Primärschlüssel (Primary Key, PK). In der Faktentabelle werden diese dann für jede Transaktion als Fremdschlüssel (Foreign Key, FK) angegeben. Über diese Schlüssel wird die Verbindung erzeugt, womit dann für jede Transaktion die Detail-Informationen zur Verfügung stehen.
Die Beispieldaten
Wir nutzen hier einfache Fantasie-Daten, die in der folgenden Abbildung zu sehen sind. In der Datenbank [EinfacherHandel] gibt es die Faktentabelle [FactTransaktionen] und die Dimensionstabellen [DimKunde] und [DimArtikel]. Nicht bei allen Transaktionen sind Kunden bzw. Artikel hinterlegt, und nicht alle aufgeführten Kunden haben eine Transaktion getätigt.
Inner Join
Oft kommt es vor, dass die Daten in einer Tabelle nicht vollständig gefüllt sind. Der Inner Join gibt nur Datensätze zurück, die in beiden beteiligten Tabellen vorhanden sind.
In der Regel beginnt man bei SQL-Joins mit der Faktentabelle. So ist auch hier die [FactTransaktionen] die „Linke Tabelle“ und die [DimKunde] die „Rechte Tabelle“. Der Code zeigt den Aufbau in T-SQL, der auch für die anderen Join-Typen gilt:
- Auswahl der relevanten Spalten mit SELECT
- Linke Tabelle mit FROM
- Rechte Tabelle nach dem JOIN-Befehl
- Prüfung auf Gleichheit der Schlüsselspalte mit ON
Optionale WHERE-Bedingungen kämen dann dahinter. Zu beachten ist noch, dass wir hier Alias-Namen für die Tabellen vergeben müssen (hier: ft und dk). Auch wenn wir hier die Kunden-ID mit PK und FK gekennzeichnet haben, haben Schlüsselspalten in der Praxis oft identische Namen in den verschiedenen Tabellen und wären ohne den Alias nicht zuzuordnen.
SELECT ft.PK_Transaktion, ft.[Datum], ft.FK_Kunde, dk.Vorname, dk.Nachname
FROM [dbo].[FactTransaktionen] ft
INNER JOIN [dbo].[DimKunde] dk
ON ft.FK_Kunde = dk.PK_Kunde
Wenn es Transaktionen gibt, bei denen kein Kunde angegeben ist, werden diese beim Inner Join nicht mit angezeigt. Das gleiche gilt für Kunden, die noch keine Transaktion getätigt haben. Im Ergebnis sieht man, dass die Datensätze mit den Transaktionsnummern 9 und 10 nicht mit aufgelistet sind. Gleiches gilt für den Kunden mit der Nummer 5.
Left/Right Outer Join
Im Gegensatz zum Inner Join werden beim Left/Right Outer Join alle Datensätze aus der Tabelle zurückgegeben, die in der Join-Anweisung links/rechts steht. Left und Right Join liefern also das gleiche Ergebnis, wenn man gleichzeitig die Reihenfolge der Tabellen im SQL-Befehl vertauscht.
SELECT ft.PK_Transaktion, ft.[Datum], ft.FK_Kunde, dk.Vorname, dk.Nachname FROM [dbo].[FactTransaktionen] ft LEFT OUTER JOIN [dbo].[DimKunde] dk ON ft.FK_Kunde = dk.PK_Kunde
In unserem Beispiel liefert der Left Join alle Transaktionen zurück, auch wenn kein Kunde hinterlegt ist. Für die abgefragten Spalten aus der Kundentabelle wird in diesen Fällen dann NULL ausgegeben.
Full Outer Join
Der Full Outer Join schließlich bezieht beide Tabellen vollständig mit ein. Auch alle NULL-Werte werden mit berücksichtigt, sodass dieser Join-Typ die höchste Zeilenzahl liefert.
SELECT ft.PK_Transaktion, ft.[Datum], ft.FK_Kunde, dk.Vorname, dk.Nachname
FROM [dbo].[FactTransaktionen] ft
FULL OUTER JOIN [dbo].[DimKunde] dk
ON ft.FK_Kunde = dk.PK_Kunde
Im Ergebnis sehen wir hier nun, dass ein weiterer Kunde aus [DimKunde] hinzugekommen ist, der noch keine Transaktionen getätigt hat. Die Kundennummer 5 wird nur deshalb nicht ausgegeben, weil wir hier die Kundennummer aus der Faktentabelle ausgeben.
Verkettung von Joins
Es lassen sich auch mehrere SQL-Joins verknüpfen. In unserem Beispiel wäre es interessant zu sehen, welche Artikel die Kunden gekauft haben. Wenn wir alle Transaktionen sehen wollen, bei denen ein Kunde eingetragen ist, auch wenn kein Artikel eingetragen ist, müssen wir zum obigen Ergebnis des INNER JOIN noch die Tabelle [DimArtikel] per LEFT JOIN hinzufügen.
SELECT ft.PK_Transaktion, ft.[Datum], ft.FK_Kunde, dk.Vorname, dk.Nachname, da.Bezeichnung, da.Preis
FROM [dbo].[FactTransaktionen] ft
INNER JOIN [dbo].[DimKunde] dk
ON ft.FK_Kunde = dk.PK_Kunde
LEFT OUTER JOIN [dbo].[DimArtikel] da
ON ft.FK_Artikel = da.PK_Artikel
Die so verknüpften Daten könnten jetzt als Grundlage für einen Power BI Report dienen, in dem visualisiert werden könnte, wie sich die Umsätze auf die Kunden bzw. Artikel aufteilen.
Fazit und Ausblick auf weitere SQL-Joins
In diesem Blogbeitrag haben wir die grundlegenden SQL-Joins sowie eine einfache Verkettung von Joins kennengelernt. In einem späteren Beitrag werden wir einen Blick auf weniger gebräuchliche und komplexere Join-Typen werfen: Den Anti-Join, den Cross Join und den Self Join.