SAE 2. Lehrjahr der Fachinformatiker

Skripte und Notizen für das 2. Lehrjahr der Fachinformatiker von Herrn Vöhringer an der GSVS

View on GitHub

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:

  1. FROM / JOIN
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. ORDER BY
  7. LIMIT

Warum HAVING existiert:

  • Nach GROUP BY entstehen Gruppen mit Aggregatwerten wie COUNT(*), AVG(...) oder SUM(...).
  • WHERE ist zu diesem Zeitpunkt bereits abgeschlossen und kann diese Gruppenergebnisse nicht mehr filtern.
  • HAVING schließ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:

  • WHERE entscheidet, welche Einzelzeilen in die Gruppierung eingehen.
  • HAVING entscheidet, 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

  1. Aggregatbedingung in WHERE statt HAVING: WHERE COUNT(*) > 5 ist nicht zulässig.
  2. Fehlende Gruppierung: HAVING mit gruppenbezogenen Aussagen ohne passendes GROUP BY führt oft zu unklarer Logik.
  3. Verwechslung der Filterebenen: Zeilenfilter gehört in WHERE, Gruppenfilter in HAVING.
  4. Unklare Operatorlogik: Bei gemischtem AND/OR Klammern 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?

Lösung **Lösung:** Weil `COUNT(*)` ein Aggregat ist. Aggregatbedingungen gehören nach der Gruppierung in `HAVING`, nicht in `WHERE`.