Alle Tabs der Lerneinheit (Erklärung · Subquery-Explorer · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Erklärung
SQL Subqueries (Sub-SELECTs)
"Gib mir alle Studierenden, die mehr Kurse belegen als der Durchschnitt." Geht das mit einem einfachen JOIN? Nein. Du brauchst eine Subquery, eine SELECT-Abfrage innerhalb einer anderen. Klausur-Pflicht in 12/12 WInf-DB-Klausuren, weil Subqueries die Brücke zwischen einfachem SQL und komplexer Datenanalyse sind.
Die Idee in einem Satz
Eine Subquery ist eine SELECT-Abfrage, deren Ergebnis als Wert oder Tabelle in eine andere Abfrage eingebaut wird.
3 typische Verwendungs-Orte:
- WHERE x IN (SELECT ...), Filter mit Liste
- WHERE EXISTS (SELECT ...), Filter mit Existenz-Test
- SELECT (SELECT ...) AS alias, Skalare Subquery in einer Spalte
Beispiel, Studi-Belegungen
Tabellen:
Studierende:
| MatrNr | Name | Semester |
|---|---|---|
| 1001 | Müller | 3 |
| 1002 | Schulz | 5 |
| 1003 | Klein | 3 |
Belegungen:
| MatrNr | KursID |
|---|---|
| 1001 | DB1 |
| 1001 | INF |
| 1002 | DB1 |
Subquery-Typen
1. WHERE x IN (Subquery)
Frage: Welche Studierenden haben DB1 belegt?
SELECT Name
FROM Studierende
WHERE MatrNr IN (
SELECT MatrNr FROM Belegungen WHERE KursID = 'DB1'
);
So liest du das:
- Innere Query zuerst: SELECT MatrNr FROM Belegungen WHERE KursID = 'DB1' → ergibt {1001, 1002}.
- Äußere Query wird zu: SELECT Name FROM Studierende WHERE MatrNr IN (1001, 1002) → Müller, Schulz.
2. WHERE EXISTS (Subquery), korreliert
Frage: Welche Studierenden haben mindestens eine Belegung?
SELECT Name
FROM Studierende s
WHERE EXISTS (
SELECT 1 FROM Belegungen b WHERE b.MatrNr = s.MatrNr
);
Das ist eine korrelierte Subquery: die innere Query referenziert die äußere (s.MatrNr). Für jede Zeile der äußeren Query wird die innere neu ausgewertet. Resultat: Müller, Schulz (nicht Klein, der hat keine Belegung).
Performance-Hinweis: Korrelierte Subqueries sind oft langsam, weil sie einmal pro äußerer Zeile laufen. Moderne Optimizer können sie aber meist in Joins umschreiben.
3. SELECT (Subquery)
Frage: Pro Studi: wie viele Kurse belegt?
SELECT
Name,
(SELECT COUNT(*) FROM Belegungen b WHERE b.MatrNr = s.MatrNr) AS Anzahl
FROM Studierende s;
Die Subquery liefert einen Skalar (genau einen Wert) pro Zeile. Ergebnis:
| Name | Anzahl |
|---|---|
| Müller | 2 |
| Schulz | 1 |
| Klein | 0 |
NOT IN vs. NOT EXISTS, die NULL-Falle
Wichtig:
NOT INundNOT EXISTSsind NICHT immer äquivalent, wenn NULL-Werte im Spiel sind.
NOT IN (SELECT ... mit NULL) ergibt leer, weil "x ≠ NULL" → UNKNOWN → ausgeschlossen.
NOT EXISTS behandelt das richtig.
Faustregel: Wenn die Subquery NULL enthalten könnte → NOT EXISTS nehmen, nicht NOT IN.
Visualisierung, verschachtelte Queries Schritt für Schritt
Schau, wie eine verschachtelte Query von innen nach außen ausgewertet wird:
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Faustregeln
- 3 Verwendungen auswendig: WHERE x IN (...), WHERE EXISTS (...), SELECT (...) AS alias.
- Lese von innen nach außen. Erst innere Query auswerten, dann äußere mit dem Ergebnis.
- Korrelierte Subquery erkennen: wenn die innere Query eine Spalte der äußeren referenziert. Klassiker mit EXISTS.
- NOT IN bei NULL-Werten ist gefährlich. Lieber NOT EXISTS verwenden.
- Skalare Subquery muss genau einen Wert liefern (sonst Laufzeit-Fehler). Bei Aggregaten (COUNT, MAX, ...) immer der Fall.
Typische Stolpersteine
1. Klammern vergessen. Subqueries MÜSSEN in runden Klammern stehen, kein "WHERE x IN SELECT ..." ohne Klammern.
2. Mehrere Zeilen in Skalar-Subquery. SELECT (SELECT name FROM ...) FROM ..., wenn die innere mehrere Zeilen liefert, knallt es zur Laufzeit. Bei "single row expected" prüfe, ob du WHERE-Bedingung vergessen hast.
3. Subquery vs. JOIN, wann was? JOIN ist meist schneller bei "x IN (...)". Subquery ist nötig bei aggregierten Vergleichen (z.B. "über dem Durchschnitt") oder Existenz-Tests.
4. SELECT-Subquery (Skalar) und WHERE-Subquery (IN) verwechseln. Skalare brauchen genau einen Wert, IN braucht eine Spalte. Falsche Stelle → SQL-Fehler.
Subquery-Explorer
Subquery-Explorer
Klicke ein Szenario, dann gehe Schritt für Schritt durch: erst die innere Query, dann die äußere. Zwischen-Ergebnis wird hervorgehoben.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Tipp: Schreib bei komplexen Subqueries die Zwischen-Ergebnisse auf einen Schmierzettel. Innere zuerst, dann äußere, Schritt für Schritt.
Praxis-Übung
SQL Subqueries, Praxis-Übung
6 Aufgaben zu IN, EXISTS, NOT-Varianten und Skalar-Subqueries.
Klausurfragen mit Lösungen (6)
- F1.Wie liest man eine Subquery typischerweise?
Antwort: Von innen nach außen
Erklärung: Von innen nach außen: erst innere Query ausführen, das Ergebnis in die äußere Query einsetzen. So entwickelt der Optimizer den Plan, und so verstehst du auch in der Klausur was passiert.
- F2.Welche Query liefert die Namen der Studierenden, die mindestens einen Kurs belegen?
Antwort: SELECT Name FROM Stud WHERE MatrNr IN (SELECT MatrNr FROM Beleg)
Erklärung: IN-Subquery: ergibt MatrNrs aus Belegungen, dann gibt Stud-Zeilen mit diesen MatrNrs. Alternative: WHERE EXISTS (SELECT 1 FROM Beleg b WHERE b.MatrNr=s.MatrNr).
- F3.Was ist eine KORRELIERTE Subquery?
Antwort: Eine Subquery, deren innere Query Spalten der äußeren Query referenziert
Erklärung: Korreliert = die innere Query bezieht sich auf eine Variable der äußeren Query. Wird einmal pro äußerer Zeile ausgewertet, kann teuer sein, aber moderne Optimizer können oft in Joins umschreiben.
- F4.NOT IN und NOT EXISTS liefern bei NULL-Werten in der Subquery immer das gleiche Ergebnis.
Antwort: Falsch
Erklärung: FALSCH. NOT IN mit NULL-Wert in der Subquery ergibt 'unknown' für jeden Vergleich und filtert ALLES aus. NOT EXISTS prüft nur Existenz und ist NULL-sicher. Klausur-Klassiker.
Typ: Wahr/Falsch
- F5.Welcher Subquery-Typ liefert genau einen Wert pro Zeile der äußeren Query?
Antwort: Skalare Subquery in SELECT
Erklärung: Skalare Subquery in SELECT: SELECT (SELECT COUNT(*) FROM Beleg b WHERE b.MatrNr = s.MatrNr) FROM Stud s. Muss genau einen Wert pro Zeile liefern, sonst Laufzeit-Fehler.
- F6.Ordne den Subquery-Operator dem Anwendungsfall zu:
Zuordnungen:
- x IN (...) → Filter mit einer Liste von Werten
- EXISTS (...) → Existenz-Test (mindestens eine Zeile)
- (SELECT ...) in SELECT → Berechne einen Wert pro äußerer Zeile
- x = ANY (...) → Vergleich mit irgendeinem Wert aus der Liste
Erklärung: Die 4 wichtigsten Subquery-Patterns. ANY/SOME ist äquivalent zu IN bei =, kann aber mit anderen Operatoren (>, <) kombiniert werden für Bereichs-Vergleiche.
Typ: Zuordnung
Klausur-Quiz
Klausurfragen mit Lösungen (6)
- F1.Welche Query liefert Studierende, die MEHR Kurse belegen als der Durchschnitt?
Antwort: SELECT MatrNr FROM Beleg GROUP BY MatrNr HAVING COUNT(*) > (SELECT AVG(c) FROM (SELECT COUNT(*) AS c FROM Beleg GROUP BY MatrNr) sub)
Erklärung: Klausur-Klassiker mit doppelt verschachtelter Subquery: innen pro Studi zählen (COUNT(*) GROUP BY MatrNr), dann den AVG dieser Zahlen, dann HAVING-Filter. Direkte Aggregat-Verschachtelungen wie AVG(COUNT(*)) sind in Standard-SQL nicht erlaubt.
- F2.Welche zwei Subquery-Varianten sind ÄQUIVALENT (außer bei NULL)?
Antwort: IN und EXISTS
Erklärung: WHERE x IN (SELECT y FROM ...) ist meist äquivalent zu WHERE EXISTS (SELECT 1 FROM ... WHERE y=x). Beide testen Existenz mit Wert-Gleichheit. NULL-Verhalten unterscheidet sich nur bei NOT-Varianten.
- F3.Sortiere die Auswertungs-Reihenfolge für: SELECT Name FROM Stud WHERE MatrNr IN (SELECT MatrNr FROM Beleg WHERE KursID = 'DB1')
Richtige Reihenfolge:
- Inner: WHERE KursID = 'DB1' filtert Beleg
- Inner: SELECT MatrNr liefert {1001, 1002}
- Outer: WHERE MatrNr IN {1001, 1002}
- Outer: SELECT Name aus passenden Stud-Zeilen
Erklärung: Innere Query immer zuerst: filtere → projeziere → das Ergebnis wird zur Liste für IN. Dann äußere Query: WHERE-Filter → SELECT.
Typ: Reihenfolge
- F4.Eine korrelierte Subquery wird einmal pro Zeile der äußeren Query ausgewertet.
Antwort: Wahr
Erklärung: Wahr, semantisch. Optimizer können das in Joins umschreiben, sodass die tatsächliche Ausführung schneller wird. Aber konzeptionell: ja, einmal pro äußerer Zeile.
Typ: Wahr/Falsch
- F5.Welche der folgenden Subquery-Patterns kann NIE eine NULL-Falle haben?
Antwort: WHERE EXISTS (...)
Erklärung: EXISTS testet nur 'gibt es mindestens eine Zeile?', NULL ist nicht relevant, weil keine Wert-Vergleiche stattfinden. NOT EXISTS ist auch sicher. IN/NOT IN haben NULL-Probleme bei Vergleichen.
- F6.Eine Subquery in WHERE mit {{1}} testet ob ein Wert in einer Liste vorkommt. Eine Subquery mit {{2}} testet ob mindestens eine Zeile existiert. Bei NULL-Werten ist {{3}} sicherer als {{4}}.
Lösungen pro Lücke:
- {{1}}: IN
- {{2}}: EXISTS
- {{3}}: NOT EXISTS
- {{4}}: NOT IN
Erklärung: Die Standard-Subquery-Operatoren plus die NULL-Falle. Klausur-Pflichtwissen.
Typ: Lückentext