Wie eine Abfrage ausgewertet wird
Du kennst jetzt alle Bestandteile einer Abfrage. Zeit für die Frage, die vieles auf einmal erklärt: In welcher Reihenfolge passiert das eigentlich?
Geschrieben wird anders als gerechnet
Eine Abfrage wird in dieser Reihenfolge geschrieben:
SELECT … 6
FROM … 1
JOIN … 1
WHERE … 2
GROUP BY … 3
HAVING … 4
ORDER BY … 7
LIMIT … 8
Ausgewertet wird sie in dieser Reihenfolge:
| Schritt | Teil | Was passiert |
|---|---|---|
| 1 | FROM / JOIN |
Die beteiligten Tabellen werden zusammengeführt. |
| 2 | WHERE |
Einzelne Zeilen werden aussortiert. |
| 3 | GROUP BY |
Die verbliebenen Zeilen werden zu Gruppen zusammengefasst. |
| 4 | HAVING |
Ganze Gruppen werden aussortiert. |
| 5 | Aggregatfunktionen | Je Gruppe wird gezählt, summiert, gemittelt. |
| 6 | SELECT |
Die Ausgabespalten werden gebildet, Aliasnamen vergeben. |
| 7 | ORDER BY |
Das Ergebnis wird sortiert. |
| 8 | LIMIT |
Die Ausgabe wird gekürzt. |
Das ist keine Kuriosität, sondern erklärt drei Dinge, die vorher wie willkürliche Regeln aussahen.
Warum COUNT im WHERE nicht funktioniert
a) Führe die Abfrage aus und lies die Fehlermeldung.
b) Erkläre mit der Auswertungsreihenfolge, warum es nicht funktionieren kann.
c) Schreibe die Abfrage so um, dass sie läuft.
Tipp
WHERE ist Schritt 2, die Aggregatfunktionen sind Schritt 5. Was gibt es zum Zeitpunkt von Schritt 2 noch gar nicht?
Warum Aliasnamen im WHERE heikel sind
Dieselbe Erklärung, nur eine Stufe subtiler. Der Alias wird in Schritt 6 vergeben, WHERE ist Schritt 2 – zu diesem Zeitpunkt kennt die Abfrage den Namen noch nicht. Nach dem SQL-Standard ist das deshalb verboten, und die meisten Systeme lehnen es ab.
Diese Abfrage läuft hier trotzdem. SQLite ist an dieser Stelle großzügiger als der Standard und sucht den Namen notfalls in der SELECT-Liste nach.
Verlass dich nicht darauf. Dieselbe Abfrage scheitert unter PostgreSQL, MySQL und den meisten anderen Systemen mit der Meldung, dass es die Spalte nicht gibt. Wiederhole im WHERE lieber den ganzen Ausdruck:
SELECT name, 2026 - gruendungsjahr AS alter_jahre
FROM band
WHERE 2026 - gruendungsjahr > 15;
Noch besser ist es, die Bedingung so umzustellen, dass sie direkt eine gespeicherte Spalte vergleicht – WHERE gruendungsjahr < 2011. Dafür kann ein Datenbanksystem einen Index nutzen; für den Ausdruck 2026 - gruendungsjahr müsste es jede Zeile einzeln ausrechnen.
Dass ein System mehr erlaubt als der Standard, ist bequem und gefährlich zugleich: Man gewöhnt sich etwas an, das anderswo nicht funktioniert, und merkt es erst beim Umzug auf ein anderes System.
Solche Abweichungen gibt es bei jedem Datenbanksystem. Wer portablen Code schreiben will, hält sich an den kleinsten gemeinsamen Nenner – auch wenn das eigene System großzügiger ist.
Warum DISTINCT und GROUP BY sich ähneln
Beide liefern dasselbe. Kein Wunder: GROUP BY fasst Zeilen mit gleichem Wert zusammen, und wenn man aus jeder Gruppe nur den Gruppierungswert ausgibt, ist das genau eine Liste der verschiedenen Werte.
Trotzdem sind sie nicht dasselbe Werkzeug. GROUP BY kann zusätzlich rechnen, DISTINCT nicht. Wo beides geht, ist DISTINCT die klarere Aussage: „Ich will jeden Wert einmal."
Eine Abfrage vorlesen
Wenn du eine fremde Abfrage verstehen willst, lies sie in der Auswertungsreihenfolge, nicht von oben nach unten:
- Womit fange ich an? (
FROM,JOIN) - Was werfe ich weg? (
WHERE) - Wie fasse ich zusammen? (
GROUP BY) - Welche Gruppen behalte ich? (
HAVING) - Was zeige ich? (
SELECT) - Wie sortiere ich? (
ORDER BY,LIMIT)
Das ist zugleich die beste Reihenfolge, um eine eigene Abfrage zu schreiben.
Lies diese Abfrage in der Auswertungsreihenfolge und beschreibe jeden Schritt in einem Satz. Sag dann voraus, wie viele Zeilen herauskommen – bevor du sie ausführst.
SELECT s.name AS buehne, COUNT(*) AS lange_auftritte
FROM auftritt AS a
JOIN buehne AS s ON s.buehne_id = a.buehne_id
WHERE a.dauer_min >= 75
GROUP BY s.name
HAVING COUNT(*) >= 3
ORDER BY lange_auftritte DESC
LIMIT 2;
Syntax, Semantik und Auswertung
- Die Syntax legt fest, in welcher Reihenfolge die Teile geschrieben werden. Ein
WHEREhinter demGROUP BYist ein Syntaxfehler. - Die Semantik legt fest, welches Ergebnis eine Abfrage bedeutet – und dafür ist die Auswertungsreihenfolge maßgeblich.
Beides fällt bei SQL auffällig auseinander: Man schreibt SELECT zuerst, gerechnet wird es fast zuletzt.
Ein Datenbanksystem darf eine Abfrage tatsächlich in beliebiger Reihenfolge ausführen – solange das Ergebnis dasselbe ist wie bei der Auswertung nach dem obigen Schema. Meistens tut es das auch: Es wird zum Beispiel filtern, bevor es verbindet, weil das viel weniger Arbeit ist.
Die Auswertungsreihenfolge beschreibt also nicht, was der Rechner tut, sondern was die Abfrage bedeutet. Genau das ist der Unterschied zwischen einer deskriptiven Sprache wie SQL und einer imperativen wie Java: In Java beschreibst du den Weg, in SQL das Ziel.