Menu

SQLite LEFT JOIN: alle Zeilen der linken Tabelle behalten

Wie LEFT JOIN in SQLite funktioniert: nicht zugeordnete Zeilen behalten, NULL-Werte richtig lesen, sauber filtern und mehrere Tabellen verknüpfen.

Diese Seite enthält ausführbare Editoren — bearbeiten, ausführen und Ausgabe sofort sehen.

LEFT JOIN behält alles aus der linken Tabelle

Ein INNER JOIN liefert nur Zeilen, bei denen auf beiden Seiten ein Treffer vorhanden ist. Oft ist genau das gewünscht – aber eben nicht immer. Manchmal ist das Fehlen eines Treffers selbst die eigentliche Antwort: Nutzer ohne Bestellung, Produkte ohne einen einzigen Verkauf, Beiträge ohne Kommentare. Für solche Fälle brauchst du den LEFT JOIN (auch LEFT OUTER JOIN genannt).

Ein LEFT JOIN gibt dir jede Zeile aus der linken Tabelle zurück. Gibt es in der rechten Tabelle einen passenden Datensatz, bekommst du dessen Spalten dazu. Falls nicht, erhältst du die Zeile aus der linken Tabelle trotzdem – und die Spalten der rechten Seite kommen als NULL zurück.

Cleo hat keine Bestellungen, taucht aber trotzdem auf – mit NULL in der Spalte total. Tauschst du LEFT JOIN gegen INNER JOIN, verschwindet Cleo komplett aus dem Ergebnis.

Das mentale Modell

Lies die Abfrage von oben nach unten und stell dir die linke Tabelle als Anker vor. Jede Zeile aus users landet in jedem Fall im Ergebnis – ohne Ausnahme. Der LEFT JOIN fragt dann für jeden Nutzer: „Gibt es dazu eine passende Zeile in orders?"

  • Treffer gefunden → die passenden Spalten werden an die User-Zeile drangehängt.
  • Mehrere Treffer → pro Treffer entsteht eine Ergebniszeile (Ada hat zwei Bestellungen und erscheint deshalb zweimal).
  • Kein Treffer → eine Zeile, in der jede Spalte aus der rechten Tabelle den Wert NULL hat.

Genau wegen des letzten Falls gibt es den LEFT JOIN überhaupt. NULL bedeutet hier nicht „wir wissen es nicht" – sondern schlicht „auf der rechten Seite gibt es nichts zum Anhängen".

LEFT OUTER JOIN ist übrigens dieselbe Operation. Das Schlüsselwort OUTER ist in SQLite optional, und in der Praxis lässt es fast jeder weg.

Zeilen ohne Treffer finden

Der Klassiker beim LEFT JOIN: Zeilen in der linken Tabelle finden, zu denen es keinen Treffer auf der rechten Seite gibt. Der Trick dabei: Du filterst auf eine Spalte aus der rechten Tabelle, die in den echten Daten NOT NULL ist – meistens ihren Primärschlüssel – und prüfst nach dem Join auf NULL:

Nur Cleo taucht wieder auf. Der Join hängt die Bestelldaten an, wo es welche gibt, und WHERE o.id IS NULL behält dann nur noch die Zeilen, bei denen das Anhängen fehlgeschlagen ist. Diese Technik nennt man auch "Anti-Join".

ON oder WHERE: die fiese Falle

Das ist der häufigste Bug bei LEFT JOIN – und genau deshalb lohnt es sich, hier kurz innezuhalten. Bedingungen kannst du entweder in die ON-Klausel oder in die WHERE-Klausel schreiben, aber bei Outer Joins verhalten sich beide völlig unterschiedlich.

  • ON greift während der Join läuft. Die Bedingungen dort legen fest, welche Zeilen aus der rechten Tabelle als Treffer gelten.
  • WHERE greift danach, also nachdem der Join seine Zeilen schon erzeugt hat. Es filtert das fertige Ergebnis.

Schau mal, was passiert, wenn du eine Bedingung für die rechte Tabelle in WHERE packst:

Cleo hat keine Bestellung, deshalb ist o.status in ihrer Zeile NULL – und NULL = 'shipped' ergibt eben nicht true. Damit fliegt sie raus. Bei Boris ist der Status 'pending', also auch weg. Der LEFT JOIN hat sich hier klammheimlich wie ein INNER JOIN verhalten.

Die Lösung: Pack die Bedingung in die ON-Klausel, damit sie die Treffer filtert und nicht die Ergebniszeilen:

Jetzt taucht jeder Nutzer auf: Ada bekommt ihre versandte Bestellung, Boris bekommt NULL (seine offene Bestellung zählt nicht als Treffer), und Cleo bekommt NULL (keine Bestellungen vorhanden). Genau das ist die richtige Antwort, wenn die Frage lautet: „Zeig mir alle Nutzer und – falls vorhanden – ihre versandten Bestellungen."

Faustregel: Bedingungen auf die linke Tabelle dürfen ins WHERE. Bedingungen auf die rechte Tabelle gehören dagegen fast immer ins ON – außer du willst gezielt mit IS NULL nach Zeilen ohne Treffer suchen. Genau hier liegt auch der typische Unterschied zwischen ON und WHERE beim SQLite LEFT JOIN.

Zeilen zählen mit LEFT JOIN in SQLite

Eine klassische Aufgabe: pro Eltern-Datensatz die zugehörigen Zeilen zählen – inklusive der Eltern, die null Treffer haben. Ein INNER JOIN würde die Nullen einfach unter den Tisch fallen lassen. Mit LEFT JOIN plus COUNT auf eine Spalte aus der rechten Tabelle bekommst du das korrekte Ergebnis:

Zwei Dinge, die hier wichtig sind:

  • COUNT(o.id) zählt nur Zeilen, bei denen die rechte Seite nicht NULL ist. Cleo bekommt deshalb 0 und nicht 1 — denn COUNT ignoriert NULL-Werte. Würdest du stattdessen COUNT(*) schreiben, käme bei Cleo 1 heraus (die Zeile existiert ja, sie hat nur NULL-Werte drin). In den allermeisten Fällen willst du COUNT(right.id).
  • COALESCE(SUM(o.total), 0) verwandelt Cleos NULL-Summe in eine 0. Ohne diesen Kniff würde bei ihr NULL als Umsatz stehen — technisch korrekt, aber unschön anzuzeigen.

SQLite LEFT JOIN über mehrere Tabellen

LEFT JOIN lässt sich verketten. Jeder Join nimmt das bisherige Zwischenergebnis und hängt eine weitere Tabelle daran. Sobald du eine Spalte durch einen LEFT JOIN nullable gemacht hast, solltest du für alle Tabellen, die daran hängen, ebenfalls LEFT JOIN verwenden — sonst wirft dir der nächste INNER JOIN klammheimlich genau die Zeilen raus, die du eigentlich behalten wolltest.

Drei User kommen zurück. Ada hat eine Bestellung und einen Versand. Boris hat eine Bestellung, aber keinen Versand (carrier ist NULL). Cleo hat überhaupt keine Bestellung, deshalb sind sowohl o.total als auch s.carrier NULL. Die Kette aus LEFT JOINs sorgt dafür, dass jeder User erhalten bleibt – egal, an welcher Stelle der Beziehungskette die Daten ausgehen.

Wann ein SQLite LEFT JOIN die richtige Wahl ist

Greif zum LEFT JOIN, wenn es bei deiner Abfrage im Kern um die linke Tabelle geht und die rechte Tabelle nur ergänzende Informationen liefert. Formulierungen wie „alle User samt ihrer Bestellungen, falls vorhanden" oder „alle Produkte mit ihrer letzten Bewertung" lassen sich direkt auf einen LEFT JOIN abbilden.

Den INNER JOIN nimmst du, wenn beide Seiten gleichermaßen vorhanden sein müssen – „Bestellungen mit den dazugehörigen User-Daten" ergibt für eine Bestellung ohne User keinen Sinn, und genau dieses Filtern erledigt der Inner Join für dich.

Wenn du dich dabei erwischst, LEFT JOIN ... WHERE right.col IS NOT NULL zu schreiben, wolltest du eigentlich einen INNER JOIN. Schreibst du dagegen LEFT JOIN ... WHERE right.col IS NULL, dann ist das ein Anti-Join – und der ist so genau richtig.

Als Nächstes: Self-Joins

Manchmal ist die Tabelle, die du dazujoinen willst, dieselbe, die du gerade abfragst – Mitarbeiter und ihre Vorgesetzten, Kategorien und ihre Oberkategorien, Paare von Usern aus derselben Stadt. Das nennt sich Self-Join, und darum geht's auf der nächsten Seite.

Häufig gestellte Fragen

Was macht ein LEFT JOIN in SQLite?

LEFT JOIN liefert dir jede Zeile aus der linken Tabelle zurück – plus die passenden Zeilen aus der rechten Tabelle, sofern es welche gibt. Findet sich rechts kein Treffer, bekommst du die linke Zeile trotzdem, und die Spalten der rechten Seite stehen dann auf NULL. LEFT OUTER JOIN bedeutet übrigens genau dasselbe – das OUTER ist in SQLite optional.

Worin unterscheiden sich LEFT JOIN und INNER JOIN in SQLite?

Ein INNER JOIN gibt nur die Zeilen zurück, bei denen die Join-Bedingung in beiden Tabellen erfüllt ist. Ein LEFT JOIN hingegen behält alle Zeilen der linken Tabelle und füllt fehlende Werte auf der rechten Seite mit NULL auf. Nimm LEFT JOIN immer dann, wenn 'kein Treffer' selbst eine Aussage ist – zum Beispiel Nutzer, die noch keine einzige Bestellung haben.

Warum verhält sich mein LEFT JOIN wie ein INNER JOIN?

In den allermeisten Fällen liegt es an einer WHERE-Klausel, die auf eine Spalte der rechten Tabelle filtert, ohne NULL zuzulassen. Bedingungen für die rechte Tabelle gehören in die ON-Klausel, nicht in WHERE – oder du schreibst bewusst WHERE right.col IS NULL, um genau die unzugeordneten Zeilen zu finden. Ein WHERE right.col = 'x' wirft dir nämlich klammheimlich alle Zeilen ohne Match wieder raus.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S