Mehrere Tabellen verknüpfen
Lerne, wie du komplexe Abfragen über drei, vier oder mehr Tabellen schreibst - mit Mehrfach-JOINs und Self-JOINs.
In der Praxis musst du oft Daten aus drei, vier oder noch mehr Tabellen kombinieren. In diesem Tutorial lernst du, wie du mehrere JOINs elegant miteinander verkettest und auch fortgeschrittene Techniken wie Self-JOINs einsetzt.
Mehrere JOINs verketten
Du kannst beliebig viele JOINs hintereinander schreiben. Jeder JOIN fuegt eine weitere Tabelle hinzu:
SELECT
k.name AS kunde,
b.bestelldatum,
p.name AS produkt,
bp.menge,
bp.einzelpreis
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;
Die Reihenfolge verstehen
Bei mehreren JOINs ist es hilfreich, den Weg der Verknuepfung zu visualisieren:
kunden ←── bestellungen ←── bestellpositionen ──→ produkte
(k.id = b.kunden_id) (b.id = bp.bestell_id) (bp.produkt_id = p.id)
Jede Tabelle wird mit einer bereits vorhandenen Tabelle verknuepft. Die Reihenfolge der JOINs kann variieren, solange die ON-Bedingung auf bereits verfuegbare Tabellen verweist.
Vollstaendige Bestelluebersicht
SELECT
k.name AS kunde,
k.stadt,
b.id AS bestell_nr,
b.bestelldatum,
b.status,
p.name AS produkt,
p.kategorie,
bp.menge,
bp.einzelpreis,
bp.menge * bp.einzelpreis AS position_total
FROM kunden k
JOIN bestellungen b ON k.id = b.kunden_id
JOIN bestellpositionen bp ON b.id = bp.bestell_id
JOIN produkte p ON bp.produkt_id = p.id
ORDER BY b.bestelldatum DESC, b.id, bp.id;
Verschiedene JOIN-Arten mischen
Du kannst INNER JOINs und LEFT JOINs in einer Abfrage mischen:
-- Alle Kunden mit ihren Bestellungen und Produkten
-- LEFT JOIN: auch Kunden ohne Bestellungen zeigen
SELECT
k.name AS kunde,
b.id AS bestell_nr,
p.name AS produkt,
bp.menge
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
LEFT JOIN bestellpositionen bp ON b.id = bp.bestell_id
LEFT JOIN produkte p ON bp.produkt_id = p.id
ORDER BY k.name, b.id;
Wichtig: Wenn du einen LEFT JOIN verwendest und danach weitere JOINs auf die rechte Tabelle aufbaust, muessen diese ebenfalls LEFT JOINs sein. Sonst werden die NULL-Zeilen wieder herausgefiltert:
-- FALSCH: INNER JOIN nach LEFT JOIN filtert NULL-Zeilen weg
SELECT k.name, b.id, bp.menge
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
JOIN bestellpositionen bp ON b.id = bp.bestell_id; -- Sarah Klein verschwindet!
-- RICHTIG: Durchgehend LEFT JOIN
SELECT k.name, b.id, bp.menge
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
LEFT JOIN bestellpositionen bp ON b.id = bp.bestell_id; -- Sarah Klein bleibt!
Self-JOIN - Eine Tabelle mit sich selbst verknuepfen
Manchmal musst du eine Tabelle mit sich selbst verknuepfen. Das nennt man einen Self-JOIN. Ein klassisches Beispiel: Mitarbeiter und ihre Vorgesetzten.
Beispiel: Mitarbeiter-Hierarchie
Erstellen wir eine Beispieltabelle:
CREATE TABLE mitarbeiter (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
position TEXT,
chef_id INTEGER REFERENCES mitarbeiter(id)
);
INSERT INTO mitarbeiter (id, name, position, chef_id) VALUES
(1, 'Maria Gross', 'CEO', NULL),
(2, 'Stefan Braun', 'CTO', 1),
(3, 'Laura Weiss', 'Teamlead', 2),
(4, 'Jan Richter', 'Entwickler', 3),
(5, 'Petra Schulz', 'Entwicklerin', 3);
-- Wer ist der Chef von wem?
SELECT
m.name AS mitarbeiter,
m.position,
c.name AS chef
FROM mitarbeiter m
LEFT JOIN mitarbeiter c ON m.chef_id = c.id;
Ergebnis:
mitarbeiter | position | chef
---------------+-------------+--------------
Maria Gross | CEO | NULL
Stefan Braun | CTO | Maria Gross
Laura Weiss | Teamlead | Stefan Braun
Jan Richter | Entwickler | Laura Weiss
Petra Schulz | Entwicklerin| Laura Weiss
Self-JOIN fuer Vergleiche
Self-JOINs sind auch nuetzlich, um Zeilen innerhalb derselben Tabelle zu vergleichen:
-- Finde Produkte, die teurer sind als andere in der gleichen Kategorie
SELECT
p1.name AS teures_produkt,
p1.preis AS teurer_preis,
p2.name AS guenstiges_produkt,
p2.preis AS guenstiger_preis
FROM produkte p1
JOIN produkte p2 ON p1.kategorie = p2.kategorie AND p1.preis > p2.preis;
Ergebnis:
teures_produkt | teurer_preis | guenstiges_produkt | guenstiger_preis
---------------+--------------+--------------------+-----------------
Jeans Classic | 49.99 | T-Shirt Basic | 19.99
Jacke Outdoor | 129.99 | T-Shirt Basic | 19.99
Jacke Outdoor | 129.99 | Jeans Classic | 49.99
Rucksack Urban | 39.99 | Muetze Winter | 14.99
CROSS JOIN - Kartesisches Produkt
Ein CROSS JOIN erzeugt alle moeglichen Kombinationen zweier Tabellen:
-- Alle Kombinationen von Produkten und Kategorien
SELECT p.name, k.stadt
FROM produkte p
CROSS JOIN kunden k;
Das Ergebnis hat Anzahl_Zeilen_A * Anzahl_Zeilen_B Zeilen. Bei grossen Tabellen wird das schnell riesig - nutze CROSS JOIN nur bewusst!
Praktischer Einsatz: Alle Moeglichkeiten generieren
-- Welche Kunden koennten welche Produkte interessant finden?
SELECT
k.name AS kunde,
p.name AS produkt,
p.preis
FROM kunden k
CROSS JOIN produkte p
WHERE p.preis < 50
ORDER BY k.name, p.preis;
Komplexe Abfragen aufbauen
Strategie: Schrittweise aufbauen
Baue komplexe Abfragen Schritt fuer Schritt auf:
-- Schritt 1: Grundabfrage
SELECT * FROM bestellungen;
-- Schritt 2: Kunden hinzufuegen
SELECT k.name, b.*
FROM bestellungen b
JOIN kunden k ON b.kunden_id = k.id;
-- Schritt 3: Positionen hinzufuegen
SELECT k.name, b.bestelldatum, bp.menge, bp.einzelpreis
FROM bestellungen b
JOIN kunden k ON b.kunden_id = k.id
JOIN bestellpositionen bp ON b.id = bp.bestell_id;
-- Schritt 4: Produkte hinzufuegen
SELECT k.name, b.bestelldatum, p.name AS produkt, bp.menge
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;
Praxisbeispiel: Umsatzreport
SELECT
k.name AS kunde,
k.stadt,
COUNT(DISTINCT b.id) AS anzahl_bestellungen,
SUM(bp.menge) AS artikel_gesamt,
ROUND(SUM(bp.menge * bp.einzelpreis), 2) AS umsatz_gesamt
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
LEFT JOIN bestellpositionen bp ON b.id = bp.bestell_id
GROUP BY k.name, k.stadt
ORDER BY umsatz_gesamt DESC;
Praxisbeispiel: Produkt-Performance
SELECT
p.name AS produkt,
p.kategorie,
p.preis,
COALESCE(SUM(bp.menge), 0) AS verkauft,
p.lagerbestand,
COALESCE(ROUND(SUM(bp.menge * bp.einzelpreis), 2), 0) AS umsatz
FROM produkte p
LEFT JOIN bestellpositionen bp ON p.id = bp.produkt_id
GROUP BY p.name, p.kategorie, p.preis, p.lagerbestand
ORDER BY umsatz DESC;
Performance-Tipps fuer JOINs
Bei grossen Datenmengen koennen JOINs langsam werden. Ein paar Tipps:
- Indizes setzen: Erstelle Indizes auf Spalten, die in ON-Klauseln verwendet werden
- Frueh filtern: Verwende WHERE, um die Datenmenge vor dem JOIN zu reduzieren
- Nur noetige Spalten: Vermeide SELECT * bei JOINs
- EXPLAIN nutzen: Analysiere den Ausfuehrungsplan
-- Schlecht: Erst joinen, dann filtern
SELECT k.name, b.betrag
FROM kunden k
JOIN bestellungen b ON k.id = b.kunden_id
JOIN bestellpositionen bp ON b.id = bp.bestell_id
JOIN produkte p ON bp.produkt_id = p.id
WHERE k.stadt = 'Berlin' AND p.kategorie = 'Kleidung';
-- Die Datenbank optimiert das meistens automatisch,
-- aber es hilft, sich der Reihenfolge bewusst zu sein.
Was kommt als Naechstes?
Im naechsten Tutorial lernst du Aggregatfunktionen wie COUNT, SUM, AVG, MIN und MAX - damit kannst du Daten zusammenfassen und statistische Auswertungen machen.
Zusammenfassung
- Du kannst beliebig viele JOINs in einer Abfrage verwenden
- Nach einem LEFT JOIN sollten weitere JOINs auf die gleiche Kette auch LEFT JOINs sein
- Self-JOINs verknuepfen eine Tabelle mit sich selbst (z.B. Hierarchien)
- CROSS JOINs erzeugen alle moeglichen Kombinationen
- Baue komplexe Abfragen Schritt fuer Schritt auf
- Achte bei vielen JOINs auf Performance (Indizes, fruehes Filtern)
Uebungen
- Drei Tabellen: Zeige alle Bestellungen mit Kundenname, Produktname und Menge.
- Vier Tabellen: Erstelle eine Detailansicht jeder Bestellung mit Kundenname, Stadt, Produkt, Kategorie, Menge und Gesamtpreis.
- LEFT JOIN Kette: Zeige alle Kunden mit ihren Bestellungen und Produkten, einschliesslich Kunden ohne Bestellungen.
- Self-JOIN: Erstelle die Mitarbeiter-Tabelle und finde alle Mitarbeiter, die den gleichen Chef haben.
- Analyse: Welche Stadt hat den hoechsten Gesamtumsatz? Nutze JOINs und GROUP BY.
-- Loesung zu Uebung 1:
SELECT
k.name AS kunde,
p.name AS produkt,
bp.menge
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;
Pro-Tipp: Wenn du eine komplexe Abfrage mit vielen JOINs debuggen musst, kommentiere die JOINs einzeln aus und fuege sie nacheinander wieder hinzu. So findest du schnell, welcher JOIN das Problem verursacht. Nutze -- am Anfang einer Zeile, um sie auszukommentieren.