Skript: Datenbanken und SQL mit der Warenautomat-Datenbank
13. HAVING
Wenn Gruppen gebildet wurden, braucht man oft noch einen Filter auf das Gruppenergebnis. Genau an dieser Stelle kommt HAVING zum Einsatz.
Die logische Verarbeitungsreihenfolge einer typischen SQL-Abfrage ist:
FROM/JOINWHEREGROUP BYHAVINGSELECTORDER BYLIMIT
Warum HAVING existiert:
- Nach
GROUP BYentstehen Gruppen mit Aggregatwerten wieCOUNT(*),AVG(...)oderSUM(...). WHEREist zu diesem Zeitpunkt bereits abgeschlossen und kann diese Gruppenergebnisse nicht mehr filtern.HAVINGschließt genau diese Lücke: Es filtert auf Gruppenebene nach der Aggregation.
13.1 Filter nach Gruppenbildung
HAVING filtert Ergebnisse nach GROUP BY. Es wirkt auf Gruppen, nicht auf einzelne Zeilen.
Grundmuster:
SELECT gruppenspalte, AGGREGAT(spalte) AS kennzahl
FROM tabelle
GROUP BY gruppenspalte
HAVING AGGREGAT(spalte) bedingung;
[!NOTE] Beispiel:
SELECT kategorie, COUNT(*) AS anzahl FROM produkt GROUP BY kategorie HAVING COUNT(*) > 5;
13.2 HAVING und WHERE
WHERE filtert vor dem Gruppieren, HAVING danach.
Merksatz:
WHEREentscheidet, welche Einzelzeilen in die Gruppierung eingehen.HAVINGentscheidet, welche Gruppen nach der Aggregation übrig bleiben.
[!NOTE] Beispiel mit beiden Ebenen:
SELECT kategorie, COUNT(*) AS anzahl, ROUND(AVG(preis_eur), 2) AS avg_preis FROM produkt WHERE aktiv = TRUE GROUP BY kategorie HAVING COUNT(*) >= 3 AND AVG(preis_eur) > 1.50;
13.3 Mehrere Bedingungen in HAVING
In HAVING können Bedingungen mit AND, OR und Klammern kombiniert werden, genau wie in WHERE.
[!NOTE] Beispiel:
SELECT l.name AS lieferant, COUNT(*) AS produktanzahl, MAX(p.preis_eur) AS teuerstes_produkt FROM lieferant l JOIN produkt p ON p.lieferant_id = l.lieferant_id GROUP BY l.name HAVING COUNT(*) >= 5 AND MAX(p.preis_eur) > 2.00;
13.4 Typische Fehler bei HAVING
- Aggregatbedingung in
WHEREstattHAVING:WHERE COUNT(*) > 5ist nicht zulässig. - Fehlende Gruppierung:
HAVINGmit gruppenbezogenen Aussagen ohne passendesGROUP BYführt oft zu unklarer Logik. - Verwechslung der Filterebenen:
Zeilenfilter gehört in
WHERE, Gruppenfilter inHAVING. - Unklare Operatorlogik:
Bei gemischtem
AND/ORKlammern setzen.
[!NOTE] Beispiel für korrekte Aufteilung:
SELECT l.name, COUNT(*) AS anzahl FROM lieferant l JOIN produkt p ON p.lieferant_id = l.lieferant_id WHERE p.aktiv = TRUE GROUP BY l.name HAVING COUNT(*) > 3;
Querverweise
(09_SQL_SELECT-Grundlagen.md)
Übungen zum Kapitel
Übung 1: Gib nur Kategorien aus, die mehr als 5 Produkte enthalten.
Lösung
**Lösung:** ```sql SELECT kategorie, COUNT(*) AS anzahl FROM produkt GROUP BY kategorie HAVING COUNT(*) > 5; ```Übung 2: Gib nur Lieferanten aus, die mehr als 10 Produkte liefern.
Lösung
**Lösung:** ```sql SELECT l.name, COUNT(*) AS anzahl FROM lieferant l JOIN produkt p ON p.lieferant_id = l.lieferant_id GROUP BY l.name HAVING COUNT(*) > 10; ```Übung 3: Warum kann man diese beiden Filter nicht immer durch WHERE ersetzen?
Lösung
**Lösung:** Weil `WHERE` vor der Gruppierung wirkt, `HAVING` aber auf das Gruppenergebnis.Übung 4: Gib alle Kategorien aus, die mindestens 3 aktive Produkte enthalten.
Lösung
**Lösung:** ```sql SELECT kategorie, COUNT(*) AS anzahl FROM produkt WHERE aktiv = TRUE GROUP BY kategorie HAVING COUNT(*) >= 3; ```Übung 5: Gib nur Lieferanten aus, deren durchschnittlicher Produktpreis über 2,00 EUR liegt.
Lösung
**Lösung:** ```sql SELECT l.name, ROUND(AVG(p.preis_eur), 2) AS durchschnittspreis FROM lieferant l JOIN produkt p ON p.lieferant_id = l.lieferant_id GROUP BY l.name HAVING AVG(p.preis_eur) > 2.00; ```Übung 6: Warum ist diese Bedingung falsch: WHERE COUNT(*) > 5?