EXISTS und NOT EXISTS
EXISTS stellt eine einfachere Frage als IN: Findet die Unterabfrage mindestens eine Zeile? Wenn ja, ist EXISTS wahr; wenn die Unterabfrage nichts findet, ist es falsch. Welche Kunden haben eine Bestellung erstattet bekommen?
SELECT k.name
FROM kunden AS k
WHERE EXISTS (
SELECT *
FROM bestellungen AS b
WHERE b.kunde_id = k.id AND b.status = 'erstattet'
)
ORDER BY k.name;| name |
|---|
| Jonas Hartmann |
| Leon Wagner |
Sieh dir die Bedingung der Unterabfrage an: b.kunde_id = k.id. Die Unterabfrage bezieht sich auf k, die Tabelle der äußeren Abfrage. Eine solche Unterabfrage heißt korreliert. Sie kann nicht für sich allein laufen (sie würde mit no such column: k.id enden), denn sie hängt von der Zeile ab, über die die äußere Abfrage gerade entscheidet. Stell dir vor, die Datenbank führt sie für jeden Kunden neu aus. Für Emma Becker ist k.id 1, und die Unterabfrage sucht nach erstatteten Bestellungen von Kunde 1. Sie findet keine, also steht Emma nicht im Ergebnis. Für Jonas Hartmann findet sie Bestellung 7, also steht er darin.
Die Unterabfragen der vorigen Übungen liefen nur einmal, und ihr Ergebnis war für jede Zeile dasselbe. Eine korrelierte Unterabfrage kann für jede Zeile eine andere Antwort geben. (Die Datenbank kann sie in Wirklichkeit auf klügere Weise ausführen, aber das Ergebnis ist dasselbe, als würde sie sie für jede Zeile ausführen.)
Was die Unterabfrage zeigt, spielt keine Rolle: EXISTS prüft nur, ob es eine Zeile gibt. Deshalb schreiben Programmierer dort SELECT * oder SELECT 1.
NOT EXISTS ist wahr, wenn die Unterabfrage nichts findet. Das sind die Kunden, die den Shop niemandem empfohlen haben, die Frage, die mit NOT IN in die Falle getappt ist:
SELECT k.name
FROM kunden AS k
WHERE NOT EXISTS (
SELECT *
FROM kunden AS gw
WHERE gw.geworben_von = k.id
)
ORDER BY k.name;| name |
|---|
| Anna Fischer |
| Hannes Schulz |
| Ida Zimmermann |
| … |
NOT EXISTS hat keine NULL-Falle: Ein Kunde, dessen geworben_von NULL ist, erfüllt die Bedingung gw.geworben_von = k.id einfach nie. Die äußere Abfrage und die Unterabfrage benutzen hier dieselbe Tabelle, also sind die Aliase k und gw Pflicht: Sie sagen, welcher Kunde welcher ist.
Typischer Fehler: die Bedingung vergessen, die die Unterabfrage mit der äußeren Zeile verbindet. WHERE EXISTS (SELECT * FROM bestellungen WHERE status = 'erstattet') fragt, ob es überhaupt eine erstattete Bestellung gibt. Die gibt es, also ist die Bedingung für jeden Kunden wahr, und die Abfrage zeigt alle 14.
So schreibst du es:
Anweisungen
- 1
Die Abfrage im Editor findet die Spiele, die niemand gekauft hat, mit
LEFT JOIN … IS NULL, wie du es in der Lektion über Joins gelernt hast. Schreibe sie mitNOT EXISTSum: Behalte die Spiele, für die die Unterabfrage keine Zeile vonpositionenmit der ID des Spiels findet. Das Ergebnis bleibt gleich:titel Lost Temple Mystery Manor Robot Rebellion - 2
Zeige darunter den Titel und den Preis der Spiele, die jemand im Angebot für weniger als den Preis des Spiels gekauft hat. Benutze
EXISTS: Die Unterabfrage sucht nach einer Zeile vonpositionendes Spiels, derenpreisniedriger ist als der Preis des Spiels. Beide Tabellen haben eine Spaltepreis, die Aliase sind also wichtig. Sortiere nach dem Titel:titel preis Shadow Ninja 25 Zombie Town 30 - 3
Benutze schließlich
NOT EXISTS, um den Namen und das Datum der Anmeldung (beigetreten) der Kunden zu zeigen, die 2024 keine Bestellung aufgegeben haben. Sortiere sie nach dem Datum der Anmeldung:name beigetreten Ida Zimmermann 2024-08-14 Greta Hoffmann 2025-02-12 Hannes Schulz 2025-05-06 Sophie Arnold 2025-08-21 Max Krause 2025-10-03