Tabellen verbinden
Ein JOIN kombiniert Zeilen aus zwei Tabellen anhand einer Bedingung, meist Fremdschlüssel = Primärschlüssel. Unsere Beispieldaten: Ben und Eva haben keine Bestellung, Bestellung 7 hat keinen Kunden.
INNER JOIN: nur Treffer auf beiden Seiten
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT k.name, b.produkt, b.preis
FROM kunden AS k
INNER JOIN bestellungen AS b ON b.kunde_id = k.id
ORDER BY k.name, b.id;name produkt preis ---- -------- ----- Mia Laptop 999.0 Mia Maus 25.5 Tom Monitor 189.9 Zoe Tastatur 49.0 Zoe Maus 25.5 Zoe Laptop 999.0
Aliase (k, b) verkürzen den Code. Bei gleichnamigen Spalten brauchst du den Tabellenpräfix.
LEFT JOIN: alle von links, Treffer von rechts
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT k.name, b.produkt
FROM kunden k
LEFT JOIN bestellungen b ON b.kunde_id = k.id
ORDER BY k.id, b.id;name produkt ---- -------- Mia Laptop Mia Maus Tom Monitor Zoe Tastatur Zoe Maus Zoe Laptop Ben Eva
Ben und Eva bleiben erhalten, ihre Bestellspalten sind NULL. So findest du Datensätze ohne Gegenstück:
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT k.name AS kunde_ohne_bestellung
FROM kunden k
LEFT JOIN bestellungen b ON b.kunde_id = k.id
WHERE b.id IS NULL;kunde_ohne_bestellung --------------------- Ben Eva
Weitere Join-Arten
| Join | Ergebnis |
|---|---|
INNER JOIN | nur Zeilen mit Treffer in beiden Tabellen |
LEFT JOIN | alle links, rechts Treffer oder NULL |
RIGHT JOIN | alle rechts (ältere SQLite-Versionen kennen es nicht; tausche einfach die Tabellen) |
FULL OUTER JOIN | alle von beiden Seiten (SQLite ab 3.39) |
CROSS JOIN | alle Kombinationen (Kreuzprodukt) |
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT k.name, b.id AS bestellung
FROM kunden k
FULL OUTER JOIN bestellungen b ON b.kunde_id = k.id
ORDER BY k.name, b.id;name bestellung
---- ----------
7
Ben
Eva
Mia 1
Mia 2
Tom 3
Zoe 4
Zoe 5
Zoe 6CREATE TABLE farben (f TEXT); CREATE TABLE groessen (g TEXT);
INSERT INTO farben VALUES ('rot'), ('blau');
INSERT INTO groessen VALUES ('S'), ('M'), ('L');
SELECT f, g FROM farben CROSS JOIN groessen ORDER BY f, g;f g ---- - blau L blau M blau S rot L rot M rot S
Joins mit Aggregation
CREATE TABLE kunden (id INTEGER PRIMARY KEY, name TEXT NOT NULL, ort TEXT, punkte INTEGER);
CREATE TABLE bestellungen (id INTEGER PRIMARY KEY, kunde_id INTEGER, produkt TEXT, preis REAL, menge INTEGER, datum TEXT);
INSERT INTO kunden VALUES (1,'Mia','Berlin',120),(2,'Tom','Hamburg',80),(3,'Zoe','Berlin',200),(4,'Ben','München',NULL),(5,'Eva','Köln',150);
INSERT INTO bestellungen VALUES
(1,1,'Laptop',999.00,1,'2025-01-10'),(2,1,'Maus',25.50,2,'2025-01-12'),(3,2,'Monitor',189.90,1,'2025-02-01'),
(4,3,'Tastatur',49.00,1,'2025-02-15'),(5,3,'Maus',25.50,1,'2025-03-03'),(6,3,'Laptop',999.00,1,'2025-03-20'),
(7,NULL,'Kabel',5.00,3,'2025-03-21');
SELECT k.name, count(b.id) AS bestellungen, COALESCE(sum(b.preis * b.menge), 0) AS umsatz
FROM kunden k
LEFT JOIN bestellungen b ON b.kunde_id = k.id
GROUP BY k.id
ORDER BY umsatz DESC;name bestellungen umsatz ---- ------------ ------ Zoe 3 1073.5 Mia 2 1050.0 Tom 1 189.9 Ben 0 0 Eva 0 0
Mehr als zwei Tabellen
CREATE TABLE studenten (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE kurse (id INTEGER PRIMARY KEY, titel TEXT);
CREATE TABLE belegungen (student_id INTEGER, kurs_id INTEGER, note REAL);
INSERT INTO studenten VALUES (1,'Mia'),(2,'Tom');
INSERT INTO kurse VALUES (1,'SQL'),(2,'Python');
INSERT INTO belegungen VALUES (1,1,1.3),(1,2,2.0),(2,1,2.7);
SELECT s.name, k.titel, b.note
FROM belegungen b
JOIN studenten s ON s.id = b.student_id
JOIN kurse k ON k.id = b.kurs_id
ORDER BY s.name, k.titel;name titel note ---- ------ ---- Mia Python 2.0 Mia SQL 1.3 Tom SQL 2.7
Self Join
Eine Tabelle mit sich selbst verbinden, z. B. Mitarbeiter und Vorgesetzte:
CREATE TABLE mitarbeiter (id INTEGER PRIMARY KEY, name TEXT, chef_id INTEGER);
INSERT INTO mitarbeiter VALUES (1,'Anna',NULL),(2,'Ben',1),(3,'Cem',1),(4,'Dina',2);
SELECT m.name AS mitarbeiter, c.name AS chef
FROM mitarbeiter m
LEFT JOIN mitarbeiter c ON c.id = m.chef_id
ORDER BY m.id;mitarbeiter chef ----------- ---- Anna Ben Anna Cem Anna Dina Ben
Merke
INNER JOIN: nur Treffer;LEFT JOIN: alle links;FULL/CROSSfür Sonderfälle- Bedingung mit
ON, Aliase für Lesbarkeit - LEFT JOIN +
WHERE rechts.id IS NULLfindet fehlende Gegenstücke - Bei Zählungen über LEFT JOIN
count(spalte_rechts)verwenden - Eine Tabelle kann mit sich selbst verbunden werden
Aufgabe
Liste alle Produkte mit dem Namen des Kunden, der sie bestellt hat, und markiere Bestellungen ohne Kunden als "unbekannt".