Lass uns nochmal auf das Thema Subqueries in SELECT zurückkommen. Besonders wichtig ist dabei, dass die innere Query auf Daten der äußeren Query zugreifen kann. Klingt erstmal easy, ist aber nicht immer ganz so simpel. Lass uns da nochmal tiefer eintauchen ...
Subqueries in SELECT erlauben es dir, zusätzliche Spalten mit berechneten Werten oder Daten einzufügen, die von anderen Datensätzen oder Tabellen abhängen. Zum Beispiel kannst du eine Liste von Studenten mit ihrem Durchschnitts-Score, der Anzahl der belegten Kurse oder dem aktuellen Maximal-Score in der Gruppe anzeigen. Das ist praktisch, wenn du Daten "on the fly" analysieren willst und Pivot-Spalten ohne vorherige Datenaufbereitung brauchst.
Grundlagen von Subqueries in SELECT
Bevor wir zu den Beispielen kommen, lass uns kurz den allgemeinen Syntax anschauen. Subqueries in SELECT sehen so aus:
SELECT column1,
column2,
(SELECT aggregation_oder_bedingung FROM andere_tabelle WHERE bedingung) AS neuer_spaltenname
FROM haupttabelle;
Beachte, dass die Subquery einen einzelnen Wert zurückgibt, der dann als neue Spalte im Ergebnis erscheint. Dabei kann die bedingung auf Spalten der haupttabelle zugreifen.
Beispiel 1: Durchschnittsnote eines Studenten hinzufügen
Starten wir mit einer einfachen und nützlichen Query: Wir haben eine Tabelle students und eine Tabelle grades, in der die Noten der Studenten gespeichert sind.
Tabelle students:
| id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Dan Seth |
Tabelle grades:
| student_id | grade |
|---|---|
| 1 | 90 |
| 1 | 85 |
| 2 | 76 |
| 3 | 88 |
| 3 | 92 |
Jetzt wollen wir eine Liste der Studenten mit ihren Namen und dem Durchschnitt ihrer Noten bekommen. Dafür nutzen wir eine Subquery im SELECT:
SELECT
s.id,
s.name,
(SELECT AVG(g.grade)
FROM grades g
WHERE g.student_id = s.id) AS average_grade
FROM students s;
Ergebnis:
| id | name | average_grade |
|---|---|---|
| 1 | Alex Lin | 87.5 |
| 2 | Anna Song | 76.0 |
| 3 | Dan Seth | 90.0 |
Hier berechnet die Subquery (SELECT AVG(g.grade) FROM grades g WHERE g.student_id = s.id) den Durchschnitt für jeden Studenten. Sie gibt für jede Zeile aus der Tabelle students einen Wert zurück – super praktisch, wenn du keinen JOIN oder vorbereitete Views machen willst.
Beispiel 2: Anzahl der Kurse pro Student zählen
Jetzt erweitern wir die Studentendaten: Wie viele Kurse besucht jeder Student? Dafür gibt's noch eine Tabelle:
Tabelle enrollments:
| student_id | course_id |
|---|---|
| 1 | 101 |
| 1 | 102 |
| 2 | 101 |
Wir geben eine Liste der Studenten mit der Anzahl der belegten Kurse aus:
SELECT
s.id,
s.name,
(SELECT COUNT(*)
FROM enrollments e
WHERE e.student_id = s.id) AS course_count -- Bezug auf Tabelle students aus der äußeren Query
FROM students s;
Ergebnis:
| id | name | course_count |
|---|---|---|
| 1 | Alex Lin | 2 |
| 2 | Anna Song | 1 |
| 3 | Dan Seth | 0 |
Die Subquery (SELECT COUNT(*) FROM enrollments e WHERE e.student_id = s.id) zählt die Einträge in der Tabelle enrollments für jeden Studenten.
Datenaggregation in Subqueries
Oft werden Subqueries in SELECT genutzt, um aggregierte Daten zu berechnen. Funktionen wie AVG, SUM, COUNT, MAX, MIN helfen dir, Daten direkt in anderen Queries zu verarbeiten.
Beispiel 3: Gesamtscore eines Studenten
Jetzt fügen wir für jeden Studenten den Gesamtscore hinzu. Dafür nehmen wir eine Subquery, die die Summe aller Noten aus der Tabelle grades berechnet:
SELECT
s.id,
s.name,
(SELECT SUM(g.grade)
FROM grades g
WHERE g.student_id = s.id) AS total_grade
FROM students s;
Ergebnis:
| id | name | total_grade |
|---|---|---|
| 1 | Alex Lin | 175 |
| 2 | Anna Song | 76 |
| 3 | Dan Seth | 180 |
Diese Subquery (SELECT SUM(g.grade) FROM grades g WHERE g.student_id = s.id) summiert die Noten jedes Studenten. Wenn ein Student keine Noten hat, ist das Ergebnis NULL, weil SUM bei fehlenden Werten NULL zurückgibt.
Einschränkungen und Tipps
- Performance. Subqueries im
SELECTwerden für jede Zeile der Haupttabelle einzeln ausgeführt. Das kann bei großen Datenmengen zu echten Verzögerungen führen. Wenn möglich, ersetze sie durchJOINoder nutze vorberechnete aggregierte Daten. Zum Beispiel:
SELECT
s.id,
s.name,
g.total_grade
FROM students s
LEFT JOIN (
SELECT student_id, SUM(grade) AS total_grade
FROM grades
GROUP BY student_id
) g ON s.id = g.student_id;
Dieser Ansatz mit JOIN ist effizienter, weil Gruppierung und Berechnung nur einmal gemacht werden.
2. Probleme mit NULL.
Wenn in der Subquery keine Daten gefunden werden, ist das Ergebnis NULL. Das kann überraschen. Beispiel:
SELECT
s.id,
s.name,
(SELECT SUM(g.grade)
FROM grades g
WHERE g.student_id = s.id) AS total_grade
FROM students s;
Wenn es für einen Studenten keine Einträge in grades gibt, ist total_grade NULL. Um NULL durch 0 zu ersetzen, nutze die Funktion COALESCE:
SELECT
s.id,
s.name,
COALESCE((SELECT SUM(g.grade)
FROM grades g
WHERE g.student_id = s.id), 0) AS total_grade
FROM students s;
Hier übergeben wir als ersten Parameter der Funktion COALESCE
(
SELECT SUM(g.grade)
FROM grades g
WHERE g.student_id = s.id
)
Subqueries in SELECT optimieren
Um unnötige Berechnungen zu vermeiden und die Performance zu verbessern:
- Nutze Indizes auf Spalten, die in Subqueries verwendet werden. Zum Beispiel beschleunigt ein Index auf
student_idin der Tabellegradesdie Filterung. - Ersetze Subqueries durch vorberechnete aggregierte Daten mit
JOIN, wenn möglich. - Begrenze die Datenmenge, die von Subqueries verarbeitet wird, durch Filter (
WHERE).
Abschließendes Beispiel: Subqueries kombinieren
Lass uns alles zusammenbringen und eine Query bauen, die Name, Durchschnittsnote, Kursanzahl und Gesamtscore eines Studenten ausgibt:
SELECT
s.id,
s.name,
(SELECT AVG(g.grade)
FROM grades g
WHERE g.student_id = s.id) AS average_grade,
(SELECT COUNT(*)
FROM enrollments e
WHERE e.student_id = s.id) AS course_count,
(SELECT SUM(g.grade)
FROM grades g
WHERE g.student_id = s.id) AS total_grade
FROM students s;
Diese Query gibt dir das komplette Studentenprofil, zusammengebaut mit der Power von Subqueries. Du siehst Durchschnitt und Gesamtscore sowie die Anzahl der belegten Kurse – alles auf einen Blick. Solche Konstruktionen sind ein super Weg, um schnell aggregierte Infos zu bekommen, ohne extra VIEWs oder JOINs zu bauen.
| id | name | average_grade | course_count | total_grade |
|---|---|---|---|---|
| 1 | Alex Lin | 87.5 | 2 | 175 |
| 2 | Anna Song | 76.0 | 1 | 76 |
| 3 | Dan Seth | 90.0 | 0 | 180 |
GO TO FULL VERSION