SQL GROUP BY & HAVING

6 Kernkonzepte
Die wichtigsten Konzepte für Gruppierung und Filterung in SQL: GROUP BY · COUNT, SUM, AVG · HAVING · Mehrfach-Gruppierung · WHERE vs HAVING · Praxis-Beispiele Mit GROUP BY fassen Sie Datensätze zu Gruppen zusammen und wenden Aggregatfunktionen an. HAVING filtert diese Gruppen – ähnlich wie WHERE, aber für Aggregationen.

GROUP BY – Daten gruppieren

GROUP BY spalte1, spalte2, ...
SELECT kategorie, COUNT(*) AS "anzahl" FROM produkte GROUP BY kategorie;

GROUP BY fasst Zeilen mit gleichen Werten in den angegebenen Spalten zu Gruppen zusammen. Zusammen mit Aggregatfunktionen wie COUNT, SUM, AVG, MIN, MAX werden gruppierte Statistiken berechnet.

Wichtige Regeln für GROUP BY

Regel Beschreibung
SELECT-Spalten Nur GROUP BY-Spalten oder Aggregatfunktionen dürfen im SELECT stehen
Reihenfolge GROUP BY steht nach WHERE und vor ORDER BY
NULL-Werte NULL-Werte werden zu einer Gruppe zusammengefasst
Mehrere Spalten Gruppierung nach Kombination mehrerer Spalten möglich
Beispiele
-- Anzahl Produkte pro Kategorie
SELECT kategorie, COUNT(*) AS "anzahl"
FROM produkte
GROUP BY kategorie;
-- Durchschnittspreis pro Kategorie
SELECT kategorie, AVG(preis) AS "durchschnitt"
FROM produkte
GROUP BY kategorie;
-- Gesamtumsatz pro Kunde
SELECT kunde_id, SUM(betrag) AS "gesamt"
FROM bestellungen
GROUP BY kunde_id;
Typische Ausgabe (Anzahl pro Kategorie):
Elektronik | 15
Bücher | 23
Kleidung | 8
Tipp: Jede Spalte im SELECT, die nicht aggregiert wird, muss in der GROUP BY-Klausel aufgeführt werden. Sonst erhalten Sie einen Fehler (in den meisten Datenbanken).

Aggregatfunktionen – COUNT, SUM, AVG, MIN, MAX

COUNT · SUM · AVG · MIN · MAX
SELECT COUNT(*) AS "zeilen", AVG(preis) AS "durchschnitt", MIN(preis) AS "min", MAX(preis) AS "max", SUM(preis) AS "summe" FROM produkte;

Aggregatfunktionen berechnen Werte über eine gesamte Gruppe oder Tabelle. Sie werden oft mit GROUP BY verwendet, können aber auch ohne GROUP BY auf die gesamte Tabelle angewendet werden.

Übersicht der Aggregatfunktionen

Funktion Beschreibung Beispiel
COUNT(*) Zählt alle Zeilen (inkl. NULL) COUNT(*) → 150
COUNT(spalte) Zählt nicht-NULL-Werte COUNT(email) → 120
COUNT(DISTINCT spalte) Zählt eindeutige nicht-NULL-Werte COUNT(DISTINCT kategorie) → 5
SUM(spalte) Summiert Werte (nur numerisch) SUM(preis) → 4520.50
AVG(spalte) Durchschnitt (nur numerisch) AVG(preis) → 90.41
MIN(spalte) Kleinster Wert MIN(preis) → 4.99
MAX(spalte) Größter Wert MAX(preis) → 999.99
Beispiele
-- Aggregat ohne GROUP BY (gesamte Tabelle)
SELECT
COUNT(*) AS "total",
AVG(preis) AS "avg_preis",
MAX(preis) AS "max_preis"
FROM produkte;
-- Mit GROUP BY: pro Kategorie
SELECT kategorie,
COUNT(*) AS "anzahl",
SUM(preis) AS "umsatz"
FROM produkte
GROUP BY kategorie;
Tipp: COUNT(DISTINCT spalte) ist nützlich, um die Anzahl unterschiedlicher Werte in einer Gruppe zu zählen – z.B. wie viele verschiedene Kategorien es gibt.

HAVING – Gruppen filtern

HAVING bedingung (nach GROUP BY)
SELECT kategorie, COUNT(*) AS "anzahl" FROM produkte GROUP BY kategorie HAVING COUNT(*) > 5;

HAVING filtert Gruppen nach der Aggregation – ähnlich wie WHERE vor der Aggregation. HAVING wird nach GROUP BY ausgeführt und kann nur Aggregatfunktionen und GROUP BY-Spalten verwenden.

WHERE vs HAVING

Merkmal WHERE HAVING
Zeitpunkt Vor GROUP BY (filtert Zeilen) Nach GROUP BY (filtert Gruppen)
Aggregatfunktionen ❌ Nicht erlaubt ✅ Erlaubt
Spalten Alle Tabellenspalten Nur GROUP BY-Spalten + Aggregate
Performance Filtert vor Aggregation (schneller) Filtert nach Aggregation
Verwendung Einzelne Zeilen filtern Gruppen filtern
Beispiele
-- Kategorien mit mehr als 5 Produkten
SELECT kategorie, COUNT(*) AS "anzahl"
FROM produkte
GROUP BY kategorie
HAVING COUNT(*) > 5;
-- Kategorien mit Durchschnittspreis > 50 €
SELECT kategorie, AVG(preis) AS "avg_preis"
FROM produkte
GROUP BY kategorie
HAVING AVG(preis) > 50;
-- Kombination: WHERE + HAVING
SELECT kategorie, COUNT(*) AS "anzahl"
FROM produkte
WHERE preis > 10 -- Filtert Zeilen VOR der Gruppierung
GROUP BY kategorie
HAVING COUNT(*) > 3; -- Filtert Gruppen NACH der Gruppierung
Tipp: Verwenden Sie WHERE, um Zeilen vor der Gruppierung zu filtern – das reduziert die zu verarbeitende Datenmenge und ist effizienter. HAVING filtern Sie erst nach der Aggregation.

Mehrfach-Gruppierung – Nach mehreren Spalten

GROUP BY spalte1, spalte2
SELECT kategorie, hersteller, COUNT(*) AS "anzahl" FROM produkte GROUP BY kategorie, hersteller;

Mehrfach-Gruppierung erstellt Gruppen für jede eindeutige Kombination der angegebenen Spalten. So erhalten Sie detailliertere Aggregationen.

Beispiele
-- Produkte pro Kategorie und Hersteller
SELECT kategorie, hersteller, COUNT(*) AS "anzahl"
FROM produkte
GROUP BY kategorie, hersteller
ORDER BY kategorie, hersteller;
-- Umsatz pro Jahr und Monat
SELECT EXTRACT('YEAR' FROM datum) AS "jahr",
EXTRACT('MONTH' FROM datum) AS "monat",
SUM(betrag) AS "umsatz"
FROM bestellungen
GROUP BY "jahr", "monat"
ORDER BY "jahr", "monat";
-- Mit HAVING auf Mehrfach-Gruppierung
SELECT kategorie, hersteller, AVG(preis) AS "avg_preis"
FROM produkte
GROUP BY kategorie, hersteller
HAVING AVG(preis) > 100;
Typische Ausgabe (Produkte pro Kategorie & Hersteller):
Elektronik | Apple | 3
Elektronik | Samsung | 4
Bücher | O'Reilly | 12
Tipp: Die Reihenfolge der Spalten in GROUP BY beeinflusst die Granularität der Gruppen. GROUP BY kategorie, hersteller erstellt feinere Gruppen als GROUP BY kategorie.

WHERE vs HAVING – Den richtigen Filter wählen

WHERE (vor GROUP BY) · HAVING (nach GROUP BY)
-- WHERE: filtert Zeilen vor der Gruppierung SELECT kategorie, COUNT(*) FROM produkte WHERE preis > 50 -- vor GROUP BY GROUP BY kategorie HAVING COUNT(*) > 3; -- nach GROUP BY

WHERE und HAVING werden oft verwechselt. WHERE filtert Zeilen vor der Gruppierung, HAVING filtert Gruppen nach der Gruppierung. Die richtige Wahl verbessert die Performance und die Korrektheit der Abfrage.

Beispiele
-- Nur Produkte über 50 € pro Kategorie zählen
SELECT kategorie, COUNT(*) AS "teure_produkte"
FROM produkte
WHERE preis > 50
GROUP BY kategorie;
-- Kategorien mit mehr als 3 teuren Produkten
SELECT kategorie, COUNT(*) AS "teure_produkte"
FROM produkte
WHERE preis > 50
GROUP BY kategorie
HAVING COUNT(*) > 3;
-- FALSCH: Aggregatfunktion in WHERE (geht nicht!)
-- SELECT kategorie, COUNT(*) FROM produkte WHERE COUNT(*) > 3 GROUP BY kategorie;
Tipp: Nutzen Sie WHERE, um irrelevante Zeilen vor der Gruppierung zu entfernen – das spart Ressourcen. HAVING verwenden Sie erst, wenn Sie die aggregierten Ergebnisse filtern möchten.

Praxis-Beispiele – GROUP BY & HAVING in Aktion

Analysen · Berichte · Statistiken
SELECT kunde_id, COUNT(*) AS "bestellungen", SUM(betrag) AS "gesamt" FROM bestellungen GROUP BY kunde_id HAVING COUNT(*) > 5 ORDER BY "gesamt" DESC;

Praxis-Beispiele zeigen die Kombination von GROUP BY und HAVING für typische Analyseaufgaben – von Kundenanalysen über Umsatzberichte bis zu Auswertungen von Bestellmustern.

Beispiele
-- Kunden mit mehr als 5 Bestellungen (umsatzstärkste zuerst)
SELECT kunde_id, COUNT(*) AS "anzahl", SUM(betrag) AS "gesamt"
FROM bestellungen
GROUP BY kunde_id
HAVING COUNT(*) > 5
ORDER BY "gesamt" DESC;
-- Monatlicher Umsatz (nur Monate mit Umsatz > 1000 €)
SELECT DATE_TRUNC('month', datum) AS "monat",
SUM(betrag) AS "umsatz"
FROM bestellungen
GROUP BY "monat"
HAVING SUM(betrag) > 1000
ORDER BY "monat";
-- Produkte, die mehr als 5 Mal bestellt wurden
SELECT p.name, COUNT(b.id) AS "bestellungen"
FROM produkte p
JOIN bestellungen b ON p.id = b.produkt_id
GROUP BY p.id, p.name
HAVING COUNT(b.id) > 5
ORDER BY "bestellungen" DESC;
-- Durchschnittlicher Bestellwert pro Kunde (nur Kunden mit > 3 Bestellungen)
SELECT kunde_id, AVG(betrag) AS "avg_wert", COUNT(*) AS "anzahl"
FROM bestellungen
GROUP BY kunde_id
HAVING COUNT(*) > 3
ORDER BY "avg_wert" DESC;
Tipp: Für komplexe Auswertungen können Sie GROUP BY mit Window Functions (z.B. ROW_NUMBER(), RANK()) kombinieren – das ermöglicht Ranglisten innerhalb von Gruppen.

GROUP BY & HAVING im Überblick

GROUP BY Gruppierung
Daten zusammenfassen
COUNT Anzahl zählen
Zeilen pro Gruppe
SUM / AVG Summieren / Durchschnitt
Numerische Werte
HAVING Gruppen filtern
Nach Aggregation
WHERE Zeilen filtern
Vor Gruppierung
ORDER BY Sortieren
Nach Gruppierung

Quick Summary

GROUP BY
Gruppieren
COUNT
Aggregieren
HAVING
Gruppen filtern
Mehrfach
Nach mehreren Spalten
WHERE
Zeilen filtern
Analysen
Praxis-Beispiele
SELECT kategorie, COUNT(*) FROM produkte GROUP BY kategorie HAVING COUNT(*) > 5;