Glückwunsch, jetzt wird’s richtig spannend! Heute schauen wir uns an, wie man verschiedene Arten von Subqueries kombiniert, um knifflige Aufgaben zu lösen. EXISTS, IN, HAVING – das magische Trio, mit dem du dich wie ein Datenbank-Zauberer fühlen wirst. Wir holen Daten aus einer Tabelle, filtern sie mit Infos aus einer anderen, gruppieren und filtern dann nochmal die Gruppen. Und als Bonus: Wir checken, wie man Abfragen noch effizienter macht.
Lass uns mit einer allgemeinen Aufgabe starten, die wir Schritt für Schritt in der Vorlesung lösen werden.
Aufgabenstellung
Stell dir vor, wir haben eine Uni-Datenbank mit drei Tabellen:
Tabelle students
| id | name | group_id |
|---|---|---|
| 1 | Otto | 101 |
| 2 | Maria | 101 |
| 3 | Alex | 102 |
| 4 | Anna | 103 |
Tabelle courses
| id | name |
|---|---|
| 1 | Mathematik |
| 2 | Programmierung |
| 3 | Philosophie |
Tabelle enrollments
| student_id | course_id | grade |
|---|---|---|
| 1 | 1 | 90 |
| 1 | 2 | NULL |
| 2 | 1 | 85 |
| 3 | 3 | 70 |
Wir sollen alle Studenten auswählen, die:
- Mindestens in einem Kurs eingeschrieben sind
EXISTS. - Mindestens in einem eingeschriebenen Kurs keine Note haben
IN. - Zu Gruppen gehören, deren Durchschnittsnote über 80 liegt
HAVING.
Lösung mit EXISTS und IN
Schritt 1: Check, wer eingeschrieben ist (EXISTS). Wir starten mit der einfachsten Bedingung. Wir wollen wissen, welche Studenten in mindestens einem Kurs eingeschrieben sind. Dafür nehmen wir EXISTS.
SELECT name
FROM students s
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE e.student_id = s.id
);
- Die äußere Abfrage holt die Namen aus der Tabelle
students. - Im Subquery checken wir, ob es Einträge in
enrollmentsgibt, die zum jeweiligen Studenten aus der äußeren Abfrage passen (WHERE e.student_id = s.id). SELECT 1zeigt einfach an, dass uns nur interessiert, ob es einen Eintrag gibt, nicht was drinsteht.
Ergebnis:
| name |
|---|
| Otto |
| Maria |
| Alex |
Jetzt wissen wir, wer eingeschrieben ist. Aber wir wollen mehr. Wir wollen nach fehlenden Noten filtern.
Schritt 2: Check auf fehlende Note (IN + NULL). Jetzt filtern wir weiter: Wir brauchen nur die Studenten, die mindestens in einem Kurs keine Note haben. Hier helfen uns IN und das Wissen, wie NULL funktioniert.
SELECT name
FROM students s
WHERE id IN (
SELECT e.student_id
FROM enrollments e
WHERE e.grade IS NULL
);
- In der äußeren Abfrage holen wir die Namen der Studenten.
- Das Subquery erstellt eine Liste von
student_idausenrollments, wograde IS NULList.
Ergebnis:
| name |
|---|
| Otto |
Also, Otto ist der einzige Student, der einen Kurs ohne Note hat. Wie dramatisch! Aber wir sind noch nicht fertig: Wir wollen nur Gruppen berücksichtigen, deren Durchschnittsnote über 80 liegt.
Lösung mit HAVING
Schritt 3: Gruppieren und Filtern mit HAVING.
Jetzt kommt alles zusammen. Wir müssen:
- Den Durchschnitt für jede Gruppe berechnen.
- Gruppen rausfiltern, deren Durchschnittsnote über 80 liegt.
- Studenten aus diesen Gruppen anzeigen, die auch die vorherigen Bedingungen erfüllen.
SELECT name
FROM students s
WHERE s.group_id IN (
SELECT group_id
FROM students
JOIN enrollments ON students.id = enrollments.student_id
WHERE grade IS NOT NULL
GROUP BY group_id
HAVING AVG(grade) > 80
)
AND id IN (
SELECT e.student_id
FROM enrollments e
WHERE e.grade IS NULL
);
- Die äußere Abfrage holt die Namen der Studenten, die alle Bedingungen erfüllen.
- Das erste Subquery im
WHEREgibt eine Liste vongroup_idfür Gruppen mit Durchschnittsnote über 80 zurück.- Wir joinen
studentsmitenrollments, um an die Noten zu kommen. - Wir filtern nur die Einträge, wo
grade IS NOT NULList. - Wir gruppieren nach
group_id. - Mit
HAVINGfiltern wir die Gruppen.
- Wir joinen
- Das zweite Subquery im
WHEREprüft, ob der Student mindestens einen Kurs ohne Note hat. - Beide Bedingungen werden mit
ANDkombiniert.
Ergebnis:
| name |
|---|
| Otto |
Wir haben also rausgefunden, dass Otto nicht nur der einzige Student ohne Note ist, sondern auch zu einer Gruppe gehört, die richtig erfolgreich ist.
Vergleich der Ansätze: EXISTS vs IN
EXISTS ist am besten, wenn du einfach nur schnell checken willst, ob es einen Eintrag gibt. Es ist effizient, weil es sofort aufhört zu suchen, sobald es den ersten Treffer findet. Das ist besonders bei großen Tabellen wichtig.
Gleichzeitig ist IN praktisch, wenn du dich auf die Inhalte konzentrierst. Zum Beispiel, wenn du eine Liste von IDs für weitere Filter brauchst. Aber denk dran: IN kann langsam werden, wenn das Subquery viele Werte zurückgibt.
Wann HAVING verwenden?
Für aggregierte Daten, bei denen du nach dem Gruppieren filtern willst, ist HAVING die beste Wahl. Aber wenn du die Bedingung in WHERE verschieben kannst (z.B. Filter auf eine Spalte), wird die Abfrage einfacher und schneller.
Komplettes Beispiel
Zur Übung noch ein Beispiel: Wähle Gruppen aus, in denen mindestens ein Student eine Note unter 75 hat, aber niemand im Kurs "Philosophie" eingeschrieben ist.
Nochmal unsere Tabellen:
Tabelle students
| id | name | group_id |
|---|---|---|
| 1 | Otto | 101 |
| 2 | Maria | 101 |
| 3 | Alex | 102 |
| 4 | Anna | 103 |
Tabelle courses
| id | name |
|---|---|
| 1 | Mathematik |
| 2 | Programmierung |
| 3 | Philosophie |
Tabelle enrollments
| student_id | course_id | grade |
|---|---|---|
| 1 | 1 | 90 |
| 1 | 2 | NULL |
| 2 | 1 | 85 |
| 3 | 3 | 70 |
SELECT DISTINCT group_id
FROM students s
WHERE group_id IN (
SELECT s.group_id
FROM students s
JOIN enrollments e ON s.id = e.student_id
WHERE e.grade < 75
)
AND group_id NOT IN (
SELECT s.group_id -- verschachtelte Abfrage 1. Ebene
FROM students s
JOIN enrollments e ON s.id = e.student_id
WHERE e.course_id = (
SELECT id FROM courses WHERE name = 'Philosophie' -- verschachtelte Abfrage 2. Ebene :P
)
);
- Das erste Subquery wählt Gruppen, in denen es Studenten mit einer Note unter 75 gibt.
- Das zweite Subquery schließt Gruppen aus, die mit dem Kurs "Philosophie" verbunden sind.
- Wir kombinieren die Bedingungen mit
INundNOT IN, um das Endergebnis zu bekommen.
Ergebnis:
| group_id |
|---|
| 101 |
Wie nützlich ist das?
Im echten Leben retten dich solche Ansätze, wenn du komplexe Datenbeziehungen analysieren musst. Zum Beispiel:
- In der Analyse, um "besondere" Kundengruppen zu finden (VIP, Problemfälle usw.).
- In Empfehlungssystemen, wo du User nach vielen Kriterien filterst.
- Im Bewerbungsgespräch, wenn du eine komplexe SQL-Abfrage optimieren sollst.
Üben, üben, üben! So wirst du zum SQL-Profi.
GO TO FULL VERSION