Die Reihenfolge der Teile einer Abfrage
Du kennst jetzt alle Teile einer Abfrage. Du schreibst sie in dieser Reihenfolge, und jeden außer SELECT kannst du weglassen:
SELECT …
FROM …
WHERE …
GROUP BY …
HAVING …
ORDER BY …
LIMIT …;Die Datenbank führt sie aber nicht in der Reihenfolge aus, in der du sie schreibst, sondern in der, in der sie sie braucht:
FROM– nimmt die Zeilen der Tabelle.WHERE– behält die Zeilen, die seine Bedingung erfüllen.GROUP BY– legt die Zeilen in Gruppen, und die Aggregatfunktionen berechnen ihre Werte für jede Gruppe.HAVING– behält die Gruppen, die seine Bedingung erfüllen.SELECT– berechnet die Spalten des Ergebnisses und benennt sie mitAS(undDISTINCTentfernt doppelte Zeilen).ORDER BY– sortiert die Zeilen des Ergebnisses.LIMIT– behält nur die ersten Zeilen (nachdem esOFFSETZeilen übersprungen hat).
Diese Reihenfolge erklärt vieles von dem, was du in dieser Lektion gesehen hast. WHERE läuft vor GROUP BY, also kann es keine Aggregatfunktionen benutzen: Es gibt noch keine Gruppen. HAVING läuft nach GROUP BY, also kann es das. Und ORDER BY läuft nach SELECT, kennt also schon die Namen, die du den Spalten gegeben hast: Deshalb funktioniert ORDER BY anzahl_spiele DESC.
Nach derselben Logik können WHERE, GROUP BY und HAVING die Aliase nicht benutzen, weil sie laufen, bevor SELECT sie erzeugt hat. In den meisten Datenbanken, wie PostgreSQL, MySQL, SQL Server oder Oracle, ist ein Alias in WHERE ein Fehler, und manche erlauben ihn auch in GROUP BY oder HAVING nicht. SQLite ist nachsichtig: Wenn es einen Namen findet, der keine Spalte der Tabelle ist, sucht es unter den Aliasen, also funktioniert das in SQLite sogar in WHERE:
SELECT titel, preis * 2 AS zwei_exemplare
FROM spiele
WHERE zwei_exemplare > 100;| titel | zwei_exemplare |
|---|---|
| Knight's Oath | 120 |
Verlass dich aber nicht darauf. Ein Alias mit dem Namen einer echten Spalte bedeutet die Spalte; ein Alias einer Aggregatfunktion kann in WHERE auch in SQLite nicht benutzt werden, weil es noch keine Gruppen gibt; und in einer anderen Datenbank funktioniert eine solche Abfrage nicht mehr. Schreibe in WHERE, GROUP BY und HAVING den Ausdruck selbst (WHERE preis * 2 > 100, HAVING COUNT(*) >= 3) und benutze Aliase in ORDER BY.
In der zweiten Abfrage dieser Übung lässt du endlich die erstatteten Bestellungen weg. Ob eine Bestellung erstattet wurde, steht in bestellungen, aber die Positionen stehen in positionen, und um beide Tabellen in einer Abfrage zu benutzen, musst du sie verbinden. Das lernst du in der Lektion über Joins, die nach einem kleinen Projekt über das bisher Gelernte kommt. Bis dahin kannst du die IDs der erstatteten Bestellungen benutzen: SELECT id FROM bestellungen WHERE status = 'erstattet'; ergibt 7 und 18, und WHERE bestellung_id NOT IN (7, 18) lässt dann ihre Positionen weg. Es ist aber ein Notbehelf: Eine von Hand geschriebene Liste von IDs ist veraltet, sobald eine weitere Bestellung erstattet wird, während eine Abfrage mit einem Join die erstatteten Bestellungen selbst findet.
So schreibst du es:
Anweisungen
- 1
Ein Kollege hat eine Abfrage geschrieben, die die Kunden mit mindestens 2 Bestellungen im Jahr 2025 zeigen soll, aber sie endet mit einem Fehler. Korrigiere sie, sodass sie Folgendes zeigt:
kunde_id bestellungen_2025 3 2 11 2 13 2 - 2
Schreibe darunter eine Abfrage, die jeden Teil benutzt. Welche Spiele haben in Bestellungen, die nicht erstattet wurden, am meisten eingebracht? Lasse aus
positionendie Positionen der erstatteten Bestellungen 7 und 18 weg (mitNOT IN, wie oben erklärt), gruppiere die Zeilen nach Spiel und zeigespiel_id, die Anzahl der verkauften Exemplare (die Summe vonmenge) in einer Spalteexemplareund die Summe vonmenge * preisin einer Spalteumsatz. Behalte nur die Spiele, von denen mindestens 3 Exemplare verkauft wurden, sortiere sie nach dem höchsten Umsatz und zeige die ersten 3:spiel_id exemplare umsatz 15 3 180 1 4 160 14 3 90