COUNT(*) vs COUNT(spalte) vs COUNT(DISTINCT spalte)
COUNT(*) zählt alle Tupel einer Gruppe inklusive Zeilen, die ausschließlich NULL-Werte enthalten. COUNT(spalte) zählt nur diejenigen Zeilen,
bei denen die angegebene Spalte einen definierten Wert ungleich NULL hat. COUNT(DISTINCT spalte) zählt die Anzahl unterschiedlicher, nicht-NULL
Ausprägungen einer Spalte, was zur Duplikate-Eliminierung dient. Diese drei Varianten liefern in der Regel unterschiedliche Zahlen und werden
gerne in Multiple-Choice-Fragen verwechselt.
Stern zählt Zeilen, Spalte zählt Werte, DISTINCT zählt Ausprägungen - NULL zählt nur der Stern mit.
NULL-Behandlung in Aggregaten
Die meisten DBMS ignorieren NULL-Werte in Aggregatfunktionen wie SUM, AVG, MIN, MAX und COUNT(spalte). Ein AVG(note) rechnet nur den Durchschnitt
der nicht-NULL Noten, wodurch der Nenner kleiner sein kann als die Gesamtzahl der Tupel. Bei einer Spalte, die ausschließlich NULL enthält, liefert
SUM/AVG/MIN/MAX ebenfalls NULL zurück, nur COUNT(*) liefert die Zeilenzahl. Diese Semantik weicht bewusst von einfachen Rechenoperationen ab, weil
NULL als unbekannt statt als 0 interpretiert wird.
NULL wird in Aggregaten übersprungen - AVG mittelt nur was da ist, nicht was fehlt.
GROUP BY - Gruppierung
GROUP BY bildet Gruppen aus Tupeln, die in einer oder mehreren Spalten gleiche Werte haben, und liefert pro Gruppe genau ein Ergebnistupel. Alle
in der SELECT-Klausel aufgeführten Attribute müssen entweder in der GROUP BY-Klausel stehen oder durch eine Aggregatfunktion umschlossen sein.
Ohne diese Regel wäre unklar, welcher Wert einer Gruppe in einer nicht aggregierten Spalte ausgegeben werden soll. Die Gruppierung erlaubt Fragen
wie Summe pro Professor oder Anzahl pro Semester.
Was nicht gruppiert wird, muss aggregiert werden - sonst Fehler.
HAVING - Filter für Gruppen
HAVING enthält Filterbedingungen, die nach der Gruppierung auf die entstandenen Gruppen angewendet werden, ähnlich zu WHERE für ungruppierte
Anfragen. In HAVING dürfen Aggregatfunktionen wie AVG(sws) >= 3 verwendet werden, in WHERE dagegen nicht. Der Unterschied ist zeitlich: WHERE
filtert einzelne Zeilen vor GROUP BY, HAVING filtert ganze Gruppen nach GROUP BY. In der Ausführungsreihenfolge steht HAVING an Position 4, nach
FROM/JOIN, WHERE und GROUP BY.
WHERE filtert Zeilen vor Gruppierung, HAVING filtert Gruppen danach.
Ausführungsreihenfolge von SQL-Klauseln
SQL wird logisch in folgender Reihenfolge ausgeführt: 1. FROM/JOIN, 2. WHERE, 3. GROUP BY, 4. HAVING, 5. SELECT, 6. DISTINCT, 7. ORDER BY,
8. Mengenoperationen. Diese Reihenfolge erklärt, warum Aliase aus SELECT nicht in WHERE genutzt werden können, aber in ORDER BY schon. Sie ist
zentral für das Verstehen komplexer Abfragen mit Aggregatfunktionen. Die Ausführungsreihenfolge unterscheidet sich absichtlich von der
Schreibreihenfolge, die mit SELECT beginnt.
FROM-WHERE-GROUP-HAVING-SELECT-DISTINCT-ORDER: erst filtern, dann gruppieren, dann aggregieren.
Die fünf Standardaggregate
AVG berechnet den arithmetischen Mittelwert nicht-NULL Werte einer numerischen Spalte. SUM addiert alle nicht-NULL Werte, MIN und MAX liefern
den kleinsten bzw. größten definierten Wert. COUNT ist die einzige Aggregatfunktion, die auch mit dem Sternoperator arbeiten kann und dann alle
Zeilen zählt. Alle Aggregate reduzieren eine Menge auf einen Skalarwert und können per AS umbenannt werden, zum Beispiel SUM(sws) AS deputat.
AVG, SUM, MIN, MAX, COUNT - fünf Aggregate reduzieren Mengen zu einem Wert.
Skalare Unterabfrage mit Aggregat
Ein häufiges Muster ist die skalare Unterabfrage, die genau einen Wert per Aggregat liefert und in WHERE mit einem Attribut verglichen wird.
Ein typisches Beispiel ist WHERE semester = (SELECT MAX(semester) FROM studenten), um den Studenten mit den meisten Semestern zu ermitteln.
Wichtig: Die Unterabfrage muss genau ein Tupel liefern, sonst gibt es einen Laufzeitfehler. Dies löst das klassische Problem, dass MAX allein nur
den Wert, aber nicht die zugehörige Zeile liefert.
MAX kennt nur den Wert - für die Zeile braucht es eine Unterabfrage.
AS-Alias für Aggregatspalten
Ergebnisse von Aggregatfunktionen bekommen ohne AS-Klausel oft einen unlesbaren automatischen Spaltennamen wie SUM(sws). Mit AS deputat wird die
Spalte klar benannt und kann in ORDER BY (nicht aber in HAVING oder WHERE der gleichen Anfrage) referenziert werden. Dies dient der Lesbarkeit und
erleichtert die Weiterverwendung in Programmen. Der AS-Operator kann auch Relationen umbenennen, zum Beispiel FROM studenten AS s.
Ohne AS bleibt SUM(sws) - mit AS wird deputat draus.