Zeilen ohne Treffer finden (Anti-Join)
Das Muster LEFT JOIN / IS NULL zum Finden verwaister und fehlender Daten
Zeilen ohne Treffer finden (Anti-Join) ist eine kostenlose SQL Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des SQL Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der SQL Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Die Anti-Join-Frage
Eine der häufigsten Fragen zu Outer Joins lautet: „Finden Sie Kunden, die noch nie eine Bestellung aufgegeben haben.“ Oder: „Listen Sie Produkte auf, die noch nie verkauft wurden“, beziehungsweise „Bestellungen ohne passenden Kunden.“
Allen diesen Aufgaben liegt dasselbe Muster zugrunde: Zeilen in einer Tabelle, für die es in einer anderen Tabelle keine Übereinstimmung gibt. Das klare Standardmuster ist der Anti-Join, aufgebaut aus einem LEFT JOIN und einem IS NULL-Filter.
Die Grundidee
Beginnen Sie mit einem LEFT JOIN: Er behält jede linke Zeile bei, und nicht passende linke Zeilen erhalten in den Spalten der rechten Tabelle den Wert NULL.
Die nicht passenden Zeilen sind also genau diejenigen, bei denen eine Spalte der rechten Tabelle NULL ist. Filtern Sie danach, und Sie isolieren die Zeilen ohne Übereinstimmung. Das ist der gesamte Trick.
Das Muster aufbauen
Hier sehen Sie den kanonischen Anti-Join, mit dem Kunden ohne Bestellungen gefunden werden. Lesen Sie ihn in zwei Schritten: LEFT JOIN behält alle Kunden, anschließend behält WHERE o.customer_id IS NULL nur die nicht passenden.
SELECT c.id, c.name
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
WHERE o.customer_id IS NULL;
-- only customers with zero ordersWarum das Schritt für Schritt funktioniert
Verfolgen Sie das Muster anhand unserer Daten, in denen Carol keine Bestellungen hat:
- LEFT JOIN erzeugt Alice (x2), Bob (x1) und Carol mit NULL in den Spalten der rechten Tabelle.
WHERE o.customer_id IS NULLverwirft Alice und Bob, weil ihre Spalten der rechten Tabelle echte Werte enthalten.- Nur Carols Zeile, also die mit NULL erzeugte Zeile, bleibt übrig.
Der Filter wird nach dem JOIN ausgeführt. Daher sieht er diese NULLs und wählt genau die verwaisten Zeilen aus.
Die richtige Spalte zum Prüfen auswählen
Prüfen Sie eine Spalte der rechten Tabelle, die bei einer tatsächlich passenden Zeile niemals legitimerweise NULL sein kann – idealerweise den JOIN-Schlüssel oder Primärschlüssel.
Wenn Sie eine nullable Spalte der rechten Tabelle wie o.shipped_at prüfen, würden Sie auch vorhandene, aber noch nicht versendete Bestellungen finden. Das wäre die falsche Antwort. Die Prüfung von o.customer_id (dem JOIN-Schlüssel) oder o.id (dem Primärschlüssel) stellt sicher, dass NULL bedeutet: „Keine Zeile hat gepasst.“
-- SAFE: join key / primary key
WHERE o.id IS NULL
-- RISKY: a nullable data column
WHERE o.shipped_at IS NULL -- catches unshipped too!Anti-Join und NOT IN
Interviewer vergleichen den Anti-Join mit NOT IN. Beide sehen gleichwertig aus, verhalten sich bei NULLs aber unterschiedlich.
Wenn die Unterabfrage irgendeinen NULL-Wert zurückgibt, liefert NOT IN überhaupt keine Zeilen. Das ist ein berüchtigter, unbemerkter Fehler. Der Anti-Join mit LEFT JOIN und IS NULL ist davon nicht betroffen.
-- DANGEROUS if any customer_id is NULL
SELECT id, name FROM customers
WHERE id NOT IN (SELECT customer_id FROM orders);
-- SAFE anti-join, same intent
SELECT c.id, c.name FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;Anti-Join und NOT EXISTS
Die andere gleichwertige Variante ist NOT EXISTS mit einer korrelierten Unterabfrage. Auch diese Variante behandelt NULLs korrekt und ist oft genauso schnell.
Alle drei Varianten (LEFT JOIN/IS NULL, NOT EXISTS und NOT IN) können Anti-Joins ausdrücken. Im Interview sollten Sie wegen ihrer NULL-Sicherheit LEFT JOIN/IS NULL oder NOT EXISTS bevorzugen. Wenn Sie die NOT-IN-Falle erwähnen, sammeln Sie Pluspunkte.
SELECT c.id, c.name
FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.id
);Ein häufiger Fehler
Ein häufiger Fehler besteht darin, die Bedingung für fehlende Übereinstimmungen in die ON-Klausel statt in WHERE zu setzen.
... ON o.customer_id = c.id AND o.id IS NULL filtert das Ergebnis nicht. Die Bedingung verändert lediglich, was als Übereinstimmung gilt, und jeder Kunde bleibt beim LEFT JOIN erhalten. Die Prüfung mit IS NULL muss in WHERE stehen und nach dem JOIN angewendet werden. Diese Falle behandeln wir in der nächsten Lektion ausführlich.
Verwaiste untergeordnete Zeilen finden
Das Muster funktioniert auch in die andere Richtung. Um Bestellungen zu finden, die auf einen fehlenden Kunden verweisen (verwaiste Zeilen, eine Prüfung der Datenintegrität), behalten Sie orders bei und prüfen die Kundenseite auf NULL.
SELECT o.id AS order_id, o.customer_id
FROM orders o
LEFT JOIN customers c
ON c.id = o.customer_id
WHERE c.id IS NULL;
-- orders pointing to a non-existent customerDie verwaisten Zeilen zählen
Oft wird nur eine Anzahl benötigt: „Wie viele Kunden haben noch nie bestellt?“ Kapseln Sie den Anti-Join oder zählen Sie direkt.
Da der Anti-Join bereits eine Zeile pro verwaistem Datensatz zurückgibt, ist ein einfaches COUNT(*) darauf hier korrekt. Es gibt genau eine Zeile pro nicht passendem Kunden.
SELECT COUNT(*) AS never_ordered
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;Die wiederverwendbare Vorlage
Merken Sie sich dieses dreizeilige Grundgerüst. Es löst eine große Gruppe von Interviewfragen:
FROM keep_table kLEFT JOIN other o ON o.fk = k.idWHERE o.id IS NULL
Vertauschen Sie Tabellen und Schlüssel, um nicht verkaufte Produkte, nicht zugewiesene Tickets, Benutzer ohne Logins oder alles zu finden, was als „X ohne passendes Y“ beschrieben wird.
Kurze Prüfung
Sie benötigen Produkte, die noch nie in order_items vorgekommen sind.
Zusammenfassung
Der Anti-Join findet Zeilen ohne Übereinstimmung: LEFT JOIN und anschließend WHERE right_key IS NULL.
- Prüfen Sie den JOIN-Schlüssel oder Primärschlüssel, niemals eine nullable Datenspalte.
- Die Prüfung mit
IS NULLgehört inWHERE, nicht inON. - Sie ist gleichwertig zu
NOT EXISTS. Bevorzugen Sie diese Variante gegenüberNOT IN, das bei NULLs fehlschlägt. - Vertauschen Sie die Tabellen, um verwaiste untergeordnete Zeilen zu finden.
Eine Vorlage, viele Fragen: „X ohne passendes Y“.
Häufig gestellte Fragen
Ist die Lektion „Zeilen ohne Treffer finden (Anti-Join)“ kostenlos?
Ja — der vollständige Text von „Zeilen ohne Treffer finden (Anti-Join)“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des SQL Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der SQL Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Zeilen ohne Treffer finden (Anti-Join)“?
Das Muster LEFT JOIN / IS NULL zum Finden verwaister und fehlender Daten Du übst SQL Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um SQL Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. SQL Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Zeilen ohne Treffer finden (Anti-Join)“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser SQL Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede SQL Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- LEFT JOIN und das Beibehalten nicht zugeordneter Zeilen
- Die Semantik von RIGHT und FULL OUTER JOIN
- Zeilen ohne Treffer finden (Anti-Join)
- Die WHERE-Falle bei OUTER JOINs