SQL GROUP BY & HAVING

6 Kernkonzepte
Die wichtigsten Konzepte zum Gruppieren und Filtern von SQL-Ergebnissen: GROUP BY · Aggregatfunktionen · HAVING · Mehrfachgruppierung · ROLLUP / CUBE · Praxisbeispiele Mit GROUP BY gruppieren Sie Datensätze und berechnen Aggregatwerte pro Gruppe. HAVING filtert die Gruppen nach Aggregatbedingungen – eine leistungsstarke Kombination für Auswertungen und Berichte.

GROUP BY – Datensätze gruppieren

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

GROUP BY gruppiert Datensätze mit gleichen Werten in den angegebenen Spalten. Zusammen mit Aggregatfunktionen wie COUNT, SUM, AVG werden gruppierte Auswertungen ermöglicht.

Wichtige Regeln für GROUP BY

Regel Beschreibung
SELECT-Spalten Nur GROUP BY-Spalten oder Aggregatfunktionen erlaubt
Reihenfolge WHERE → GROUP BY → HAVING → ORDER BY
NULL-Werte NULL wird als eigene Gruppe behandelt
Mehrere Spalten Gruppierung nach Kombination der Spalten
Alias Im GROUP BY kann der Spalten-Alias verwendet werden
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 (COUNT pro Kategorie):
Elektronik | 12
Bücher | 8
Kleidung | 5
Tipp: GROUP BY ohne Aggregatfunktion ist äquivalent zu SELECT DISTINCT. Der Unterschied: GROUP BY ist die Grundlage für weitere Aggregationen.

Aggregatfunktionen – COUNT, SUM, AVG, MIN, MAX

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

Aggregatfunktionen berechnen Werte über eine Gruppe von Zeilen. Sie werden häufig mit GROUP BY kombiniert, können aber auch ohne GROUP BY auf die gesamte Tabelle angewendet werden.

Die wichtigsten Aggregatfunktionen

Funktion Beschreibung Beispiel
COUNT(*) Zählt alle Zeilen (auch NULL) COUNT(*) FROM produkte
COUNT(spalte) Zählt Zeilen mit nicht-NULL-Wert COUNT(rabatt) FROM produkte
COUNT(DISTINCT spalte) Zählt eindeutige Werte COUNT(DISTINCT kategorie)
SUM(spalte) Summiert alle Werte SUM(preis) FROM produkte
AVG(spalte) Durchschnittswert AVG(preis) FROM produkte
MIN(spalte) Kleinster Wert MIN(preis) FROM produkte
MAX(spalte) Größter Wert MAX(preis) FROM produkte
Beispiele
-- Gesamtstatistik aller Produkte
SELECT
COUNT(*) AS "anzahl",
SUM(preis) AS "gesamt",
AVG(preis) AS "durchschnitt",
MIN(preis) AS "min",
MAX(preis) AS "max"
FROM produkte;
-- Eindeutige Kategorien zählen
SELECT COUNT(DISTINCT kategorie) AS "kategorien"
FROM produkte;
Typische Ausgabe:
anzahl | gesamt | durchschnitt | min | max
25 | 12499.75| 499.99 | 9.99 | 999.99
Tipp: COUNT(*) zählt alle Zeilen, COUNT(spalte) ignoriert NULL-Werte. COUNT(DISTINCT spalte) ist nützlich für die Anzahl eindeutiger Werte.

HAVING – Gruppen nach Aggregatwerten filtern

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

HAVING filtert Gruppen nach Aggregatbedingungen. WHERE filtert einzelne Zeilen (vor GROUP BY), HAVING filtert Gruppen (nach GROUP BY).

HAVING vs WHERE

Merkmal WHERE HAVING
Zeitpunkt Vor GROUP BY Nach GROUP BY
Aggregatfunktionen ❌ Nicht erlaubt ✅ Erlaubt
Spalten Alle Tabellenspalten GROUP BY-Spalten oder Aggregate
Alias ❌ Nicht erlaubt ✅ Erlaubt (meistens)
Beispiele
-- Kategorien mit mehr als 5 Produkten
SELECT kategorie, COUNT(*) AS "anzahl"
FROM produkte
GROUP BY kategorie
HAVING COUNT(*) > 5;
-- Kunden mit Gesamtumsatz über 1000 €
SELECT kunde_id, SUM(betrag) AS "gesamt"
FROM bestellungen
GROUP BY kunde_id
HAVING SUM(betrag) > 1000;
-- Kategorien mit durchschnittlichem Preis > 100
SELECT kategorie, AVG(preis) AS "durchschnitt"
FROM produkte
GROUP BY kategorie
HAVING AVG(preis) > 100;
-- Kombination mit WHERE (Vorab-Filter)
SELECT kategorie, COUNT(*) AS "anzahl"
FROM produkte
WHERE bestand > 0 -- Nur verfügbare Produkte
GROUP BY kategorie
HAVING COUNT(*) > 3;
Typische Ausgabe (Kategorien mit > 5 Produkten):
Elektronik | 12
Bücher | 8
Tipp: HAVING ohne GROUP BY ist möglich, aber dann wird die gesamte Tabelle als eine Gruppe behandelt – das ist selten nützlich.

Mehrfachgruppierung – Nach mehreren Spalten

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

Mehrfachgruppierung gruppiert nach der Kombination mehrerer Spalten. Jede eindeutige Kombination bildet eine eigene Gruppe.

Beispiele
-- Produkte pro Kategorie und Hersteller
SELECT kategorie, hersteller, COUNT(*) AS "anzahl"
FROM produkte
GROUP 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 Mehrfachgruppierung
SELECT kategorie, hersteller, COUNT(*) AS "anzahl"
FROM produkte
GROUP BY kategorie, hersteller
HAVING COUNT(*) > 3;
Typische Ausgabe (Kategorie + Hersteller):
Elektronik | Apple | 5
Elektronik | Samsung | 4
Bücher | Springer | 3
Tipp: Bei Mehrfachgruppierung werden alle Kombinationen der GROUP BY-Spalten gebildet. Die Reihenfolge im GROUP BY beeinflusst die Hierarchie für ROLLUP/CUBE.

ROLLUP / CUBE – Zwischensummen & Kreuztabellen

GROUP BY ROLLUP · GROUP BY CUBE
SELECT kategorie, hersteller, COUNT(*) AS "anzahl" FROM produkte GROUP BY ROLLUP (kategorie, hersteller);

ROLLUP erzeugt Zwischensummen für jede Hierarchie-Ebene. CUBE erzeugt alle möglichen Kombinationen (Kreuztabellen). Diese Funktionen sind in PostgreSQL, SQL Server, Oracle und MySQL (8.0+) verfügbar.

ROLLUP vs CUBE

Funktion Ergebnis Anzahl Gruppen
ROLLUP(a, b, c) (a,b,c), (a,b), (a), () – Hierarchisch n + 1
CUBE(a, b, c) Alle Kombinationen: (a,b,c), (a,b), (a,c), (b,c), (a), (b), (c), () 2n
GROUPING() Zeigt an, ob ein Wert aggregiert ist (1 = aggregiert) Für SELECT
Beispiele
-- ROLLUP: Zwischensummen pro Kategorie und Gesamtsumme
SELECT
COALESCE(kategorie, 'Alle') AS "kategorie",
COALESCE(hersteller, 'Zwischensumme') AS "hersteller",
COUNT(*) AS "anzahl"
FROM produkte
GROUP BY ROLLUP (kategorie, hersteller);
-- CUBE: Alle Kombinationen (Kreuztabelle)
SELECT
COALESCE(kategorie, 'Alle') AS "kategorie",
COALESCE(hersteller, 'Alle') AS "hersteller",
COUNT(*) AS "anzahl"
FROM produkte
GROUP BY CUBE (kategorie, hersteller);
-- Mit GROUPING(): Welche Zeile ist aggregiert?
SELECT
GROUPING(kategorie) AS "kategorie_agg",
GROUPING(hersteller) AS "hersteller_agg",
kategorie, hersteller, COUNT(*) AS "anzahl"
FROM produkte
GROUP BY ROLLUP (kategorie, hersteller);
Typische Ausgabe (ROLLUP):
Elektronik | Apple | 5
Elektronik | Samsung | 4
Elektronik | Zwischensumme | 9
Bücher | Springer | 3
Bücher | Zwischensumme | 3
Alle | Alle | 12
Tipp: ROLLUP und CUBE sind leistungsstark für Berichte und Dashboards. GROUPING() hilft, aggregierte Zeilen in der Anwendung zu erkennen und zu formatieren.

Praxis-Beispiele – GROUP BY & HAVING in Aktion

Berichte · Analysen · Statistiken
SELECT kategorie, SUM(preis) AS "umsatz" FROM produkte GROUP BY kategorie HAVING SUM(preis) > 1000;

Praxis-Beispiele zeigen typische Anwendungen von GROUP BY und HAVING für Berichte, Analysen und statistische Auswertungen.

Beispiele
-- Umsatz pro Kategorie (nur Kategorien mit Umsatz > 1000)
SELECT kategorie, SUM(preis) AS "umsatz"
FROM produkte
GROUP BY kategorie
HAVING SUM(preis) > 1000;
-- Top 5 Kunden nach Bestellanzahl
SELECT kunde_id, COUNT(*) AS "bestellungen"
FROM bestellungen
GROUP BY kunde_id
ORDER BY "bestellungen" DESC
LIMIT 5;
-- Monatliche Verkaufsstatistik (mit HAVING)
SELECT
TO_CHAR(datum, 'YYYY-MM') AS "monat",
COUNT(*) AS "anzahl",
SUM(betrag) AS "umsatz"
FROM bestellungen
GROUP BY "monat"
HAVING SUM(betrag) > 5000
ORDER BY "monat";
-- Produkte pro Kategorie mit durchschnittlichem Preis
SELECT
kategorie,
COUNT(*) AS "anzahl",
MIN(preis) AS "min",
MAX(preis) AS "max",
AVG(preis) AS "durchschnitt"
FROM produkte
GROUP BY kategorie;
Typische Ausgabe (Produkte pro Kategorie):
Elektronik | 12 | 9.99 | 999.99 | 249.99
Bücher | 8 | 4.99 | 49.99 | 19.99
Tipp: Kombinieren Sie GROUP BY mit ORDER BY und LIMIT für Ranglisten. Für komplexe analytische Abfragen sind Window Functions (z.B. RANK, DENSE_RANK) oft die bessere Wahl.

GROUP BY & HAVING im Überblick

GROUP BY Datensätze gruppieren
Grundlage für Aggregate
COUNT Zeilen zählen
* oder Spalte
SUM/AVG Summe/Durchschnitt
Nur numerische Spalten
HAVING Gruppen filtern
Nach Aggregatwerten
ROLLUP Zwischensummen
Hierarchische Auswertung
CUBE Alle Kombinationen
Kreuztabellen

Quick Summary

GROUP BY
Gruppieren
COUNT
Aggregieren
HAVING
Gruppen filtern
Mehrere
Mehrfachgruppierung
ROLLUP
Zwischensummen
Berichte
Analysen
SELECT kategorie, COUNT(*) FROM produkte GROUP BY kategorie HAVING COUNT(*) > 5;