Die Reihenfolge der Ausführung einer Abfrage
Kurz gesagt: Eine SQL-Abfrage wird mit SELECT am Anfang geschrieben, aber die Datenbank führt sie in der Reihenfolge FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT aus.
Problem
Hier geht es, dort nicht
In der Lektion über Gruppen hat ORDER BY month den Alias aus SELECT benutzt. In der Lektion über HAVING haben wir das ganze SUM(...) wiederholt, und SUM in WHERE hat einen Fehler gegeben. Warum funktioniert ein Alias an einer Stelle und an einer anderen nicht?
Die Antwort liegt in der Reihenfolge, in der die Datenbank die Abfrage liest. Es ist nicht die Reihenfolge, in der du sie schreibst.
Die Idee
In einer Reihenfolge geschrieben, in einer anderen ausgeführt
Du schreibst so:
SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT
Die Datenbank denkt so:
FROM: woher die Zeilen kommen;WHERE: welche Zeilen bleiben;GROUP BY: die Gruppen;HAVING: welche Gruppen bleiben;SELECT: was angezeigt wird und wie es heißt;ORDER BY: die Sortierung;LIMIT: wie viele Zeilen.
Das ist die logische Ausführungsreihenfolge einer Abfrage. Die drei geschäftigsten Monate, ohne die stornierten Bestellungen:
Schritt für Schritt: FROM nimmt die 60 Bestellungen. WHERE entfernt die 7 stornierten, es bleiben 53. GROUP BY teilt sie in 14 Monate. HAVING behält die sechs mit mindestens 5 Bestellungen. SELECT berechnet Monat und Anzahl und benennt sie. ORDER BY sortiert sie, und LIMIT nimmt die ersten drei.
Genauer, für Neugierige
Das ist die Reihenfolge, in der die Abfrage scheinbar läuft. Der echte Plan kann anders sein: Die Datenbank darf einen Index benutzen oder einen Schritt überspringen, solange das Ergebnis dasselbe ist. Mit Abfrageplänen beschäftigen wir uns im Modul über Indizes.
Die Idee
Warum der Alias in ORDER BY funktioniert
Der Alias entsteht in SELECT, in Schritt 5. ORDER BY ist Schritt 6, also existiert der Name schon:
Die drei größten Bestellungen. Das funktioniert in jeder Datenbank. In WHERE, GROUP BY und HAVING existiert der Alias nach der Regel noch nicht, weil sie vor SELECT kommen.
Probier es aus
Die aktivsten Kunden
Zeige die fünf Kunden mit den meisten Bestellungen: customer_id und die Anzahl in einer Spalte namens orders, die meisten zuerst. Bei Gleichstand kommt die kleinere customer_id zuerst.
Lösung
SELECT customer_id, COUNT(*) AS orders
FROM orders
GROUP BY customer_id
ORDER BY orders DESC, customer_id
LIMIT 5;GROUP BY customer_id, COUNT(*) AS orders, ORDER BY orders DESC, customer_id, LIMIT 5. Die zweite Spalte in ORDER BY zählt: Die Kunden 4, 7 und 11 haben je 4 Bestellungen, und gleich neun Kunden haben 3. Ohne sie ist nicht versprochen, wer Fünfter wird.
Sieh es dir an
Was SQLite verzeiht
Nach der Regel sollte ein Alias in WHERE nicht funktionieren. Die Produkte, die mit 20 % Rabatt unter 1 € kosten:
SQLite akzeptiert es. Es akzeptiert einen Alias auch in GROUP BY:
Andere Datenbanken sind nicht so nachsichtig. PostgreSQL akzeptiert einen Alias in GROUP BY, aber nicht in WHERE: Dort meldet es, dass es die Spalte sale nicht gibt. SQL Server akzeptiert ihn weder in WHERE noch in GROUP BY.
Die Nachsicht von SQLite hat Grenzen. Wenn der Alias genauso heißt wie eine Spalte, nimmt WHERE die Spalte:
Es kommen zwei Produkte heraus, nicht vier: WHERE price < 1 schaut auf den echten Preis, nicht auf den reduzierten. Und ein Alias eines Aggregats in WHERE ist weiterhin „misuse of aggregate“, weil es in Schritt 2 noch keine Gruppen gibt:
Eine Abfrage, die überall funktioniert: In WHERE den Ausdruck wiederholen (WHERE price * 0.8 < 1) und Aliase in ORDER BY frei benutzen.
Übung
Der Monatsbericht
Die Inhaberin will einen Bericht für 2026: für jeden Monat, wie viele Bestellungen es gibt (ohne die stornierten) und von wie vielen verschiedenen Kunden. Monate mit weniger als 3 Bestellungen sind ihr zu ruhig, die braucht sie nicht.
Zeige die Spalten month (Jahr-Monat), orders und customers für die Monate 2026 mit mindestens 3 Bestellungen, ohne die stornierten zu zählen, in der Reihenfolge der Monate.
Lösung
SELECT strftime('%Y-%m', ordered_at) AS month,
COUNT(*) AS orders,
COUNT(DISTINCT customer_id) AS customers
FROM orders
WHERE status <> 'cancelled' AND ordered_at >= '2026-01-01'
GROUP BY strftime('%Y-%m', ordered_at)
HAVING COUNT(*) >= 3
ORDER BY month;Jeder Teil steht an seinem Platz:
WHERE status <> 'cancelled' AND ordered_at >= '2026-01-01': die Zeilen;GROUP BY strftime('%Y-%m', ordered_at): die Monate;HAVING COUNT(*) >= 3: die Gruppen;COUNT(*) AS orders, COUNT(DISTINCT customer_id) AS customers: die Spalten;ORDER BY month: die Reihenfolge.
Sechs Monate. Im September stammen 7 Bestellungen von 6 Kunden: Einer von ihnen hat zweimal bestellt.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Datumsfunktionen · Aggregatfunktionen: COUNT, SUM, AVG · GROUP BY: ein Bericht nach Gruppen · HAVING: Bedingung für Gruppen
- Geht weiter in: Fensterfunktionen · Die Bäckerei, Etappe 3: die Fragen
- Aufgaben zum Thema: Zusammenfassen