SQL-JOINs verständlich – INNER JOIN vs. LEFT JOIN
Zwei Tabellen zusammenführen ist Alltag – und die häufigste Fehlerquelle ist der falsche JOIN-Typ. Ich erkläre dir INNER JOIN und LEFT JOIN an einem konkreten Beispiel und warum ein LEFT JOIN dir Zeilen „verstecken" kann, wenn du im WHERE nicht aufpasst.
Sobald Daten auf mehrere Tabellen verteilt sind, brauchst du JOINs, um sie in einer Abfrage zusammenzuführen. Nehmen wir zwei Tabellen: kunden und bestellungen (jede Bestellung verweist über kunde_id auf einen Kunden).
INNER JOIN – nur Treffer auf beiden Seiten
SELECT k.name, b.betrag
FROM kunden k
INNER JOIN bestellungen b ON b.kunde_id = k.id;Ein INNER JOIN liefert nur Zeilen, für die es auf beiden Seiten einen passenden Eintrag gibt. Ein Kunde ohne Bestellung taucht hier nicht auf. Das ist genau richtig, wenn du z. B. „alle bezahlten Bestellungen mit Kundennamen" willst.
LEFT JOIN – alle Kunden, auch ohne Bestellung
SELECT k.name, b.betrag
FROM kunden k
LEFT JOIN bestellungen b ON b.kunde_id = k.id;Ein LEFT JOIN behält jede Zeile der linken Tabelle (kunden) – auch die ohne passende Bestellung. Für diese Kunden ist b.betrag dann schlicht NULL. Perfekt für Fragen wie „welche Kunden haben noch nie bestellt?":
SELECT k.name
FROM kunden k
LEFT JOIN bestellungen b ON b.kunde_id = k.id
WHERE b.id IS NULL; -- kein Treffer rechts → Kunde ohne BestellungDie Falle: Bedingung im WHERE statt im ON
Ein Klassiker, der schon vielen die Auswertung verhagelt hat. Du willst einen LEFT JOIN, filterst aber die rechte Tabelle im WHERE:
-- ⚠️ verhält sich wie ein INNER JOIN!
SELECT k.name, b.betrag
FROM kunden k
LEFT JOIN bestellungen b ON b.kunde_id = k.id
WHERE b.betrag > 100;Sobald b.betrag NULL ist (Kunde ohne Bestellung), ist NULL > 100 nicht wahr – die Zeile fliegt raus. Der LEFT JOIN ist damit wirkungslos. Willst du die Bedingung nur auf die Verknüpfung anwenden, gehört sie ins ON:
SELECT k.name, b.betrag
FROM kunden k
LEFT JOIN bestellungen b
ON b.kunde_id = k.id AND b.betrag > 100; -- Kunden bleiben erhaltenMerksatz
- INNER JOIN: Schnittmenge – nur was zusammenpasst.
- LEFT JOIN: linke Tabelle komplett, rechte wo vorhanden, sonst
NULL. - Filter auf die optionale (rechte) Seite gehört ins
ON, nicht insWHERE.
Das gilt in SQLite, PostgreSQL, MySQL und SQL Server gleich. Wenn du ein Projekt mit ordentlich modellierter Datenbank brauchst, baue ich dir Struktur und Abfragen dahinter – meld dich über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Laufende Summe in SQL – SUM() OVER statt Schleife in der Anwendung
Kontostand nach jeder Buchung, kumulierter Umsatz im Jahr, Restbestand nach jeder Entnahme: Alles dieselbe Frage. Mit einer Fensterfunktion beantwortet die Datenbank sie in einer Abfrage – inklusive gleitendem Durchschnitt.
NULL in SQL – warum COUNT(spalte) lügt und wo die leeren Werte landen
NULL ist kein Wert, sondern die Abwesenheit eines Werts. Deshalb zählt COUNT(spalte) anders als COUNT(*), summiert SUM() an leeren Zeilen vorbei und landen beim Sortieren alle Lücken am selben Ende.
Wie viel mehr als gestern? Differenz zur Vorzeile mit LAG() in SQL
„Wie viele Besucher heute im Vergleich zu gestern?" – der Reflex ist ein Self-Join auf die Vorzeile. Mit der Fensterfunktion LAG() bekommst du den Wert der vorherigen Zeile direkt daneben, ohne die Tabelle ein zweites Mal anzufassen.