JOIN-Arten (INNER, LEFT, RIGHT)
Meistere alle JOIN-Arten: INNER JOIN, LEFT JOIN, RIGHT JOIN und FULL OUTER JOIN - mit anschaulichen Beispielen und Vergleichen.
Im letzten Tutorial hast du den INNER JOIN kennengelernt. Aber was, wenn du auch Kunden sehen willst, die noch nie bestellt haben? Oder Produkte, die noch nie verkauft wurden? Dafuer gibt es verschiedene JOIN-Arten.
Die vier JOIN-Arten im Ueberblick
| JOIN-Art | Zeigt |
|---|---|
| INNER JOIN | Nur Zeilen mit Uebereinstimmung in beiden Tabellen |
| LEFT JOIN | Alle Zeilen der linken Tabelle + Uebereinstimmungen rechts |
| RIGHT JOIN | Alle Zeilen der rechten Tabelle + Uebereinstimmungen links |
| FULL OUTER JOIN | Alle Zeilen aus beiden Tabellen |
Unsere Beispieldaten
Zur Erinnerung - unsere Tabellen:
kunden: bestellungen:
+----+---------------+--------+ +----+-----------+--------+
| id | name | stadt | | id | kunden_id | betrag |
+----+---------------+--------+ +----+-----------+--------+
| 1 | Anna Schmidt | Berlin | | 1 | 1 | 69.98 |
| 2 | Max Mueller | Hamburg| | 2 | 1 | 129.99 |
| 3 | Lisa Weber |Muenchen| | 3 | 2 | 94.98 |
| 4 | Tom Becker | Berlin | | 4 | 3 | 19.99 |
| 5 | Sarah Klein | Koeln | | 5 | 4 | 184.97 |
+----+---------------+--------+ +----+-----------+--------+
Beachte: Sarah Klein (ID 5) hat keine Bestellung.
INNER JOIN
Der INNER JOIN zeigt nur Zeilen, bei denen es in beiden Tabellen eine Uebereinstimmung gibt:
SELECT k.name, b.id AS bestell_id, b.betrag
FROM kunden k
INNER JOIN bestellungen b ON k.id = b.kunden_id;
Ergebnis:
name | bestell_id | betrag
--------------+------------+-------
Anna Schmidt | 1 | 69.98
Anna Schmidt | 2 | 129.99
Max Mueller | 3 | 94.98
Lisa Weber | 4 | 19.99
Tom Becker | 5 | 184.97
Sarah Klein fehlt - sie hat keine Bestellung.
LEFT JOIN (LEFT OUTER JOIN)
Der LEFT JOIN zeigt alle Zeilen der linken Tabelle. Wenn es keine Uebereinstimmung in der rechten Tabelle gibt, werden die rechten Spalten mit NULL gefuellt:
SELECT k.name, b.id AS bestell_id, b.betrag
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id;
Ergebnis:
name | bestell_id | betrag
--------------+------------+-------
Anna Schmidt | 1 | 69.98
Anna Schmidt | 2 | 129.99
Max Mueller | 3 | 94.98
Lisa Weber | 4 | 19.99
Tom Becker | 5 | 184.97
Sarah Klein | NULL | NULL
Sarah Klein erscheint jetzt - mit NULL-Werten fuer die Bestelldaten.
Wann braucht man LEFT JOIN?
LEFT JOIN ist extrem nuetzlich, wenn du alle Datensaetze einer Tabelle sehen willst, unabhaengig davon, ob es verknuepfte Daten gibt:
-- Alle Kunden MIT Anzahl ihrer Bestellungen (auch Kunden ohne Bestellungen)
SELECT
k.name,
COUNT(b.id) AS anzahl_bestellungen
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
GROUP BY k.name
ORDER BY anzahl_bestellungen DESC;
Ergebnis:
name | anzahl_bestellungen
--------------+--------------------
Anna Schmidt | 2
Lisa Weber | 1
Max Mueller | 1
Tom Becker | 1
Sarah Klein | 0
Nur Zeilen OHNE Uebereinstimmung finden
Ein cleverer Trick: LEFT JOIN + WHERE IS NULL findet Datensaetze ohne Verknuepfung:
-- Kunden, die noch nie bestellt haben
SELECT k.name, k.email
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
WHERE b.id IS NULL;
Ergebnis:
name | email
------------+-------------------
Sarah Klein | sarah@example.com
-- Produkte, die noch nie bestellt wurden
SELECT p.name, p.preis
FROM produkte p
LEFT JOIN bestellpositionen bp ON p.id = bp.produkt_id
WHERE bp.id IS NULL;
RIGHT JOIN (RIGHT OUTER JOIN)
Der RIGHT JOIN ist das Gegenteil des LEFT JOIN - er zeigt alle Zeilen der rechten Tabelle:
SELECT k.name, b.id AS bestell_id, b.betrag
FROM bestellungen b
RIGHT JOIN kunden k ON b.kunden_id = k.id;
Ergebnis (identisch zum LEFT JOIN, nur die Tabellenreihenfolge ist anders):
name | bestell_id | betrag
--------------+------------+-------
Anna Schmidt | 1 | 69.98
Anna Schmidt | 2 | 129.99
Max Mueller | 3 | 94.98
Lisa Weber | 4 | 19.99
Tom Becker | 5 | 184.97
Sarah Klein | NULL | NULL
LEFT JOIN vs. RIGHT JOIN
In der Praxis wird LEFT JOIN viel haeufiger verwendet als RIGHT JOIN. Jeder RIGHT JOIN kann als LEFT JOIN umgeschrieben werden - man muss nur die Tabellenreihenfolge tauschen:
-- Diese beiden Abfragen liefern das gleiche Ergebnis:
-- RIGHT JOIN:
SELECT k.name, b.betrag
FROM bestellungen b
RIGHT JOIN kunden k ON b.kunden_id = k.id;
-- LEFT JOIN (umgedreht):
SELECT k.name, b.betrag
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id;
Empfehlung: Nutze immer LEFT JOIN und schreibe die “Haupttabelle” links. Das ist lesbarer und konsistenter.
FULL OUTER JOIN
Der FULL OUTER JOIN zeigt alle Zeilen aus beiden Tabellen. Wo keine Uebereinstimmung existiert, steht NULL:
SELECT k.name, b.id AS bestell_id, b.betrag
FROM kunden k
FULL OUTER JOIN bestellungen b ON k.id = b.kunden_id;
Hinweis: SQLite unterstuetzt FULL OUTER JOIN nicht direkt. In PostgreSQL funktioniert er aber problemlos.
Wann braucht man FULL OUTER JOIN?
FULL OUTER JOIN ist selten noetig. Ein typischer Anwendungsfall ist der Datenabgleich:
-- Abgleich zweier Listen: Welche Kunden haben Bestellungen und welche Bestellungen haben Kunden?
SELECT
k.name,
b.id AS bestell_id,
CASE
WHEN k.id IS NULL THEN 'Bestellung ohne Kunde'
WHEN b.id IS NULL THEN 'Kunde ohne Bestellung'
ELSE 'Alles ok'
END AS status
FROM kunden k
FULL OUTER JOIN bestellungen b ON k.id = b.kunden_id;
Visuelle Darstellung
So kannst du dir die JOIN-Arten vorstellen:
INNER JOIN: LEFT JOIN: RIGHT JOIN: FULL OUTER JOIN:
┌───┐ ┌───┐ ┌───┐ ┌───┐
│ A ├──┤ B │ █ A ├──┤ B │ │ A ├──█ B │ █ A ├──█ B │
└───┘ └───┘ └───┘ └───┘
Nur Schnitt- Alles aus A, Alles aus B, Alles aus A
menge Schnittmenge B Schnittmenge A und B
Praxisbeispiele
Kundenreport mit Bestellstatistik
SELECT
k.name,
k.stadt,
COUNT(b.id) AS anzahl_bestellungen,
COALESCE(SUM(b.betrag), 0) AS gesamtumsatz,
COALESCE(ROUND(AVG(b.betrag), 2), 0) AS durchschnitt
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
GROUP BY k.name, k.stadt
ORDER BY gesamtumsatz DESC;
Ergebnis:
name | stadt | anzahl | gesamtumsatz | durchschnitt
--------------+----------+--------+--------------+-------------
Anna Schmidt | Berlin | 2 | 199.97 | 99.99
Tom Becker | Berlin | 1 | 184.97 | 184.97
Max Mueller | Hamburg | 1 | 94.98 | 94.98
Lisa Weber | Muenchen | 1 | 19.99 | 19.99
Sarah Klein | Koeln | 0 | 0.00 | 0.00
Produktverkaufsanalyse
SELECT
p.name AS produkt,
p.kategorie,
COALESCE(SUM(bp.menge), 0) AS verkaufte_menge,
p.lagerbestand
FROM produkte p
LEFT JOIN bestellpositionen bp ON p.id = bp.produkt_id
GROUP BY p.name, p.kategorie, p.lagerbestand
ORDER BY verkaufte_menge DESC;
Bestelldetails mit allen Infos
SELECT
k.name AS kunde,
k.stadt,
b.bestelldatum,
p.name AS produkt,
bp.menge,
bp.einzelpreis,
bp.menge * bp.einzelpreis AS position_gesamt
FROM bestellungen b
JOIN kunden k ON b.kunden_id = k.id
JOIN bestellpositionen bp ON b.id = bp.bestell_id
JOIN produkte p ON bp.produkt_id = p.id
ORDER BY b.bestelldatum DESC, k.name;
Welchen JOIN soll ich verwenden?
| Situation | JOIN-Art |
|---|---|
| Nur zusammenpassende Daten | INNER JOIN |
| Alle aus der Haupttabelle, auch ohne Verknuepfung | LEFT JOIN |
| Datensaetze ohne Verknuepfung finden | LEFT JOIN + WHERE IS NULL |
| Datenabgleich beider Seiten | FULL OUTER JOIN |
| Standard fuer die meisten Faelle | LEFT JOIN |
Was kommt als Naechstes?
Im naechsten Tutorial lernst du, wie du noch komplexere Abfragen mit mehreren Tabellen und verschachtelten JOINs erstellst.
Zusammenfassung
- INNER JOIN zeigt nur Datensaetze mit Uebereinstimmung in beiden Tabellen
- LEFT JOIN zeigt alle Datensaetze der linken Tabelle (NULL wo keine Verknuepfung)
- RIGHT JOIN zeigt alle der rechten Tabelle (nutze lieber LEFT JOIN)
- FULL OUTER JOIN zeigt alle Datensaetze beider Tabellen
- LEFT JOIN + WHERE IS NULL findet Datensaetze ohne Verknuepfung
- In der Praxis: LEFT JOIN ist der am haeufigsten verwendete JOIN
Uebungen
- LEFT JOIN: Zeige alle Produkte mit ihrer Verkaufsmenge. Produkte ohne Verkaeufe sollen 0 zeigen.
- Ohne Verknuepfung: Finde alle Kunden, die noch nie bestellt haben.
- Vergleich: Schreibe die gleiche Abfrage einmal mit INNER JOIN und einmal mit LEFT JOIN. Vergleiche die Ergebnisse.
- Praxis: Erstelle einen Bericht, der fuer jeden Kunden den Namen, die Anzahl Bestellungen und den Gesamtumsatz zeigt - auch fuer Kunden ohne Bestellungen.
- Analyse: Welche Produkte wurden noch nie bestellt?
-- Loesung zu Uebung 2:
SELECT k.name, k.email
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
WHERE b.id IS NULL;
-- Loesung zu Uebung 5:
SELECT p.name, p.preis
FROM produkte p
LEFT JOIN bestellpositionen bp ON p.id = bp.produkt_id
WHERE bp.id IS NULL;
Pro-Tipp: Wenn du nicht sicher bist, welchen JOIN du brauchst, starte mit einem LEFT JOIN. So siehst du alle Datensaetze der Haupttabelle und die NULL-Werte zeigen dir genau, wo keine Verknuepfung existiert. Dann kannst du entscheiden, ob du diese Zeilen behalten oder mit WHERE filtern moechtest.