Gruppieren wie ein Profi: GROUP BY vs. HAVING anhand echter Use-Cases erklärt

Wenn du mit SQL arbeitest, wirst du schnell merken: Es ist eine Sache, Daten zu sammeln, aber eine ganz andere, sie sinnvoll zusammenzufassen. Genau hier kommt die Gruppierung ins Spiel.

Durch das Aggregieren von Daten – also das Zusammenfassen ähnlicher Zeilen – kannst du wertvolle Insights gewinnen, die in einem riesigen Datenchaos sonst untergehen würden. Zum Beispiel: Umsatz pro Kunde, durchschnittliche Bewertung pro Produkt oder die Performance einer Abteilung.

Doch viele Anfänger stolpern genau an einer Stelle: GROUP BY vs. HAVING. Beide sind für die Gruppierung wichtig, aber ihr Einsatzzeitpunkt und Zweck sind unterschiedlich – und das führt oft zu Verwirrung. In diesem Artikel räumen wir mit diesem Durcheinander auf. Anhand praxisnaher Business-Szenarien zeige ich dir Schritt für Schritt, wann du GROUP BY einsetzt, wann HAVING und warum die Kombination beider oft Gold wert ist. Am Ende wirst du SQL-Abfragen schreiben können, die sauber aggregieren und exakt die Ergebnisse liefern, die du brauchst.

SQL Group By Having

Grundlagen von GROUP BY und HAVING

GROUP BY

Mit GROUP BY fasst du mehrere Zeilen zusammen, die denselben Wert in einer oder mehreren Spalten teilen. Das Ergebnis sind sogenannte Aggregations-Gruppen oder „Buckets“. Innerhalb dieser Gruppen kannst du dann Berechnungen wie Summe, Durchschnitt oder Anzahl durchführen.

Beispiel: Du möchtest wissen, wie viel Umsatz jeder Kunde insgesamt gemacht hat. Hier gruppierst du die Bestellungen nach customer_id und summierst die Beträge.

  • Arbeitet mit Aggregatfunktionen wie SUM, COUNT, AVG
  • Erzeugt eine neue Sicht auf die Daten auf Gruppenbasis

HAVING

HAVING kommt ins Spiel, nachdem die Daten gruppiert wurden. Es funktioniert ähnlich wie WHERE, filtert aber die Ergebnisse von Aggregatfunktionen. Mit anderen Worten: HAVING erlaubt dir, nur die Gruppen anzuzeigen, die bestimmte Bedingungen erfüllen.

Beispiel: Du möchtest nur Kunden sehen, deren Gesamtumsatz über 1.000 € liegt. HAVING filtert genau diese Gruppen.

Wichtiger Unterschied

WHERE filtert die Rohdaten, bevor sie gruppiert werden. HAVING filtert die Daten nach der Gruppierung. Das ist entscheidend, denn Aggregatfunktionen wie SUM oder AVG kannst du nicht in WHERE verwenden.

Use-Case 1: Kundenanalyse (E-Commerce)

Problemstellung

Du möchtest herausfinden, welche Kunden im Jahr 2023 mehr als 1.000 € ausgegeben haben. Das ist eine typische Frage im E-Commerce, um VIP-Kunden zu identifizieren oder gezielte Marketingaktionen zu planen.

Lösungsschritte

SELECT customer_id, SUM(order_amount) AS total_spent
FROM orders
WHERE order_date >= '2023-01-01'  -- Filter VOR Gruppierung (WHERE!)
GROUP BY customer_id              -- Gruppiere Kunden
HAVING SUM(order_amount) > 1000;  -- Filter NACH Gruppierung (HAVING!)

Erklärung

  • WHERE order_date >= '2023-01-01': Filtert alle Bestellungen, die nicht aus 2023 stammen. Dieser Schritt passiert vor der Gruppierung.
  • GROUP BY customer_id: Fasst die Bestellungen pro Kunde zusammen, sodass wir pro Kunde den Gesamtumsatz berechnen können.
  • HAVING SUM(order_amount) > 1000: Zeigt nur die Kunden, deren aggregierter Umsatz über 1.000 € liegt. Dieser Filter kommt nach der Gruppierung.

Warum nicht nur WHERE?

WHERE entfernt einzelne Zeilen aus der Datenbasis – zum Beispiel alle Bestellungen vor 2023. HAVING hingegen filtert das Ergebnis der Aggregation, also die summierten Umsätze pro Kunde. Ohne HAVING würdest du auch Kunden sehen, deren Umsatz unter 1.000 € liegt.

Use-Case 2: Produktbewertungen filtern (Review-System)

Problemstellung

Du möchtest nur Produkte anzeigen, die eine durchschnittliche Bewertung von mindestens 4,5 haben und gleichzeitig mindestens 20 Bewertungen erhalten haben. Das hilft dir, Bestseller und besonders beliebte Produkte schnell zu identifizieren.

Lösungsschritte

SELECT product_id, AVG(rating) AS avg_rating, COUNT(*) AS num_reviews
FROM reviews
GROUP BY product_id              -- Gruppiere nach Produkt
HAVING AVG(rating) >= 4.5     -- Filter Aggregat 1: ⌀-Bewertung
   AND COUNT(*) >= 20;        -- Filter Aggregat 2: Anzahl Reviews

Erklärung

  • GROUP BY product_id: Fasst alle Bewertungen pro Produkt zusammen.
  • AVG(rating) >= 4.5: Zeigt nur Produkte mit einer durchschnittlichen Bewertung von 4,5 oder höher.
  • COUNT(*) >= 20: Stellt sicher, dass nur Produkte mit mindestens 20 Bewertungen angezeigt werden.
Mit HAVING kannst du mehrere Aggregat-Bedingungen kombinieren. So lässt sich sehr genau steuern, welche Gruppen (Produkte) tatsächlich angezeigt werden sollen.

Use-Case 3: Mitarbeiter-Performance (HR-Reporting)

Problemstellung

Du möchtest herausfinden, in welchen Abteilungen die durchschnittliche Deal-Größe über 50.000 € liegt, aber nur für Teams mit mehr als 5 Mitarbeitern. Das ist ein typisches Reporting im Sales- oder HR-Bereich.

Lösungsschritte

SELECT department, AVG(deal_size) AS avg_deal_size
FROM sales
GROUP BY department              -- Gruppiere nach Abteilung
HAVING AVG(deal_size) > 50000  -- Filter Aggregat 1: ⌀-Deal-Größe
   AND COUNT(employee_id) > 5; -- Filter Aggregat 2: Mitarbeiteranzahl

Erklärung

  • GROUP BY department: Fasst alle Deals pro Abteilung zusammen.
  • AVG(deal_size) > 50000: Filtert Abteilungen mit einer durchschnittlichen Deal-Größe über 50.000 €.
  • COUNT(employee_id) > 5: Zeigt nur Abteilungen mit mehr als 5 Mitarbeitern. COUNT ignoriert automatisch NULL-Werte.

Profi-Tipp

Wenn du mehrere Aggregat-Bedingungen kombinierst, ist HAVING dein bester Freund. So kannst du gezielt Abteilungen oder Gruppen herausfiltern, die deinen Kriterien entsprechen.

Fehlerfalle: Wann WHERE vs. HAVING?

Typischer Anfängerfehler

Viele Anfänger versuchen, Aggregatfunktionen direkt in WHERE zu verwenden. Das führt zu Fehlern, weil WHERE vor der Gruppierung angewendet wird und Aggregatfunktionen noch nicht berechnet wurden.

-- FALSCH: WHERE kann nicht mit Aggregaten arbeiten!
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 5000  -- ERROR!
GROUP BY department;

Korrektur

Aggregat-Bedingungen müssen immer in HAVING stehen:

SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 5000;

Goldene Regel

  1. Schritt 1: Rohdaten filtern → WHERE
  2. Schritt 2: Gruppieren → GROUP BY
  3. Schritt 3: Gruppierte Ergebnisse filtern → HAVING

Best Practices für Profis

Performance

Filtere deine Daten zuerst mit WHERE, bevor du gruppierst. So reduziert sich die Datenmenge, die GROUP BY verarbeiten muss, und Abfragen laufen schneller.

Lesbarkeit

Verwende Aliase in HAVING für Aggregatfunktionen. Das macht deinen Code klarer und leichter verständlich. Beispiel:

SELECT customer_id, SUM(order_amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING total_spent > 1000;

Komplexe Logik

Bei mehreren Aggregaten nutze HAVING mit logischen Operatoren wie AND oder OR. So kannst du sehr gezielt Gruppen filtern:

SELECT department, AVG(deal_size) AS avg_deal_size, COUNT(employee_id) AS team_size
FROM sales
GROUP BY department
HAVING AVG(deal_size) > 50000
   AND COUNT(employee_id) > 5;

Fazit: Die Reihenfolge ist wichtig

Filtere deine Daten zuerst mit WHERE, bevor du gruppierst.
So reduziert sich die Datenmenge, die GROUP BY verarbeiten muss, und Abfragen laufen schneller.

Verwende Aliase in HAVING für Aggregatfunktionen.
Das macht deinen Code klarer und leichter verständlich. Beispiel:

SELECT customer_id, SUM(order_amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING total_spent > 1000;

Bei mehreren Aggregaten nutze HAVING mit logischen Operatoren wie AND oder OR.
So kannst du sehr gezielt Gruppen filtern:

SELECT department, AVG(deal_size) AS avg_deal_size, COUNT(employee_id) AS team_size
FROM sales
GROUP BY department
HAVING AVG(deal_size) > 50000
   AND COUNT(employee_id) > 5;