SQL GROUP BY und Aggregatfunktionen: Fasse deine Daten zusammen
Published: 2026-04-08
GROUP BY fasst mehrere Zeilen, die in einer oder mehreren Spalten denselben Wert haben, zu einer einzigen Zusammenfassungszeile zusammen. In Kombination mit Aggregatfunktionen wie COUNT, SUM, AVG, MIN und MAX bildet es die Grundlage fast jeder Reporting- und Analyseabfrage. GROUP BY wird in allen SQL-Datenbanken unterstützt, darunter SQLite, PostgreSQL, MySQL, SQL Server und Oracle.
Beispieldaten
Wir verwenden in allen Beispielen zwei Tabellen:
employees-Tabelle:
| id | name | department | hire_date | salary |
|---|---|---|---|---|
| 1 | Alice | Engineering | 2023-01-15 | 95000 |
| 2 | Bob | Engineering | 2023-06-01 | 85000 |
| 3 | Carol | Engineering | 2024-03-10 | 85000 |
| 4 | Dave | Sales | 2023-02-20 | 72000 |
| 5 | Eve | Sales | 2023-09-05 | 68000 |
| 6 | Frank | Sales | 2024-01-15 | 65000 |
| 7 | Grace | Marketing | 2023-04-01 | 82000 |
| 8 | Henry | Marketing | 2024-06-01 | 70000 |
orders-Tabelle:
| id | customer | product | category | quantity | unit_price | order_date | status |
|---|---|---|---|---|---|---|---|
| 1 | Acme Corp | Laptop Pro | Electronics | 3 | 1299.99 | 2026-01-05 | delivered |
| 2 | Acme Corp | Wireless Mouse | Electronics | 10 | 29.99 | 2026-01-12 | delivered |
| 3 | Globex | Office Chair | Furniture | 5 | 249.99 | 2026-01-18 | delivered |
| 4 | Globex | Standing Desk | Furniture | 2 | 599.99 | 2026-01-20 | shipped |
| 5 | Initech | Notebook Pack | Stationery | 20 | 12.99 | 2026-02-03 | delivered |
| 6 | Initech | Pen Set | Stationery | 15 | 8.99 | 2026-02-07 | delivered |
| 7 | Acme Corp | Monitor 27" | Electronics | 4 | 399.99 | 2026-02-14 | delivered |
| 8 | Umbrella Ltd | Laptop Pro | Electronics | 2 | 1299.99 | 2026-02-20 | cancelled |
| 9 | Umbrella Ltd | Desk Lamp | Furniture | 8 | 39.99 | 2026-03-01 | delivered |
| 10 | Globex | Wireless Mouse | Electronics | 12 | 29.99 | 2026-03-05 | shipped |
| 11 | Initech | Monitor 27" | Electronics | 1 | 399.99 | 2026-03-10 | delivered |
| 12 | Acme Corp | Standing Desk | Furniture | 1 | 599.99 | 2026-03-15 | processing |
GROUP BY-Syntax
SELECT column1, aggregate_function(column2)
FROM table_name
WHERE condition
GROUP BY column1
HAVING aggregate_condition
ORDER BY column1;
- GROUP BY — eine oder mehrere Spalten, deren unterschiedliche Wertekombinationen jede Gruppe definieren
- Aggregatfunktionen — berechnen einen einzelnen Wert aus allen Zeilen der Gruppe
- HAVING — filtert Gruppen (ähnlich wie WHERE, aber für gruppierte Ergebnisse)
- Jede Spalte in SELECT, die nicht in einer Aggregatfunktion steht, muss in GROUP BY erscheinen
Ausführungsreihenfolge von SQL
SQL-Klauseln werden in einer Reihenfolge geschrieben, aber in einer anderen Reihenfolge ausgeführt. Das erklärt, warum HAVING auf Aggregatfunktionen zugreifen kann, WHERE aber nicht, und warum du einen SELECT-Alias nicht in einer HAVING-Klausel verwenden kannst.
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
| Schritt | Klausel | Was passiert |
|---|---|---|
| 1 | FROM | Lädt die Tabelle(n) und wertet alle JOINs aus |
| 2 | WHERE | Filtert einzelne Zeilen — Aggregatfunktionen sind hier nicht erlaubt |
| 3 | GROUP BY | Fasst die verbleibenden Zeilen zu Gruppen zusammen |
| 4 | HAVING | Filtert Gruppen — Aggregatfunktionen sind hier erlaubt |
| 5 | SELECT | Berechnet Ausgabespalten und Aliasse |
| 6 | ORDER BY | Sortiert das endgültige Ergebnisset |
Darum läuft WHERE status = 'delivered' vor dem Gruppieren (schneller, zeilenweiser Filter), während HAVING COUNT(*) > 2 nach dem Gruppieren ausgeführt wird (filtert ganze Gruppen).
COUNT()
COUNT(*) zählt alle Zeilen in einer Gruppe. COUNT(column) zählt Nicht-NULL-Werte in dieser Spalte.
Beispiel: Anzahl der Mitarbeitenden pro Abteilung
Beispiel: Anzahl der Bestellungen pro Kunde
Beispiel: Gelieferte vs. andere Status zählen
Zähle nur Bestellungen, die einer Bedingung entsprechen, mit COUNT und einem CASE-Ausdruck:
SUM()
SUM(column) addiert alle Werte in der Gruppe für eine numerische Spalte.
Beispiel: Gesamtsalär pro Abteilung
Beispiel: Gesamtumsatz pro Kategorie
Berechne den Umsatz als quantity * unit_price:
Beispiel: Umsatz nach Kunde und Kategorie
Gruppiere nach mehreren Spalten, um den Umsatz weiter aufzuschlüsseln:
AVG()
AVG(column) gibt den arithmetischen Mittelwert aller Nicht-NULL-Werte in der Gruppe zurück.
Beispiel: Durchschnittsgehalt pro Abteilung
Beispiel: Durchschnittlicher Bestellwert pro Kunde
MIN() und MAX()
MIN(column) und MAX(column) geben den kleinsten bzw. größten Wert in der Gruppe zurück.
Beispiel: Gehaltsspanne pro Abteilung
Beispiel: Erstes und letztes Bestelldatum pro Kunde
Mehrere Aggregate kombinieren
Du kannst beliebig viele Aggregatfunktionen in einer einzigen Abfrage kombinieren.
Beispiel: Vollständige Abteilungsübersicht
Beispiel: Bestellübersicht pro Kunde
HAVING
HAVING filtert Gruppen nach der Aggregation — es ist das Äquivalent zu WHERE für gruppierte Ergebnisse.
Beispiel: Abteilungen mit mehr als zwei Mitarbeitenden
Beispiel: Kunden mit Gesamtumsatz über 2000
Beispiel: Kategorien mit durchschnittlichem Bestellwert unter 500
WHERE vs. HAVING
WHERE filtert einzelne Zeilen vor dem Gruppieren. HAVING filtert Gruppen nach der Aggregation.
Beispiel: Umsatz nur aus gelieferten Bestellungen pro Kunde
Verwende WHERE, um Zeilen vor dem Gruppieren auszuschließen, und dann HAVING, um Ergebnisse zu filtern:
GROUP BY mit JOINs
Du kannst Daten gruppieren, die sich über mehrere Tabellen erstrecken, indem du sie zuerst verbindest (JOIN).
Beispiel: Umsatz pro Abteilung über Join mit Employees
Beispiel: Bestellanzahl und Umsatz pro Kategorie und Monat
GROUP BY mit Ausdrücken
Du kannst nach berechneten Ausdrücken gruppieren, nicht nur nach einfachen Spalten.
Beispiel: Mitarbeitendeinstellungen pro Jahr
Beispiel: Bestellungen pro Monat
COUNT(DISTINCT)
COUNT(DISTINCT column) zählt die Anzahl der eindeutigen Werte in der Gruppe.
Beispiel: Eindeutige Produkte pro Kunde
Gruppen mit mehreren Bedingungen filtern
HAVING unterstützt jeden booleschen Ausdruck, einschließlich AND/OR-Kombinationen.
Beispiel: Wertvolle aktive Kunden
Finde Kunden mit mehr als einer Bestellung und einem Gesamtumsatz über 1000:
Praxisbeispiel: Verkaufsbericht
Kombiniere alles zu einem vollständigen Verkaufsübersichtsbericht.
Beispiel: Leistungsbericht nach Kategorie
Beispiel: Top-Produkt nach Umsatz
GROUP BY vs. Window-Funktionen
GROUP BY fasst Zeilen zu einer Zeile pro Gruppe zusammen. Window-Funktionen behalten alle Zeilen bei und fügen eine berechnete Spalte hinzu — Details findest du im SQL-Tutorial zu Window-Funktionen.
Beispiel: GROUP BY gibt eine Zeile pro Abteilung zurück
Beispiel: Window-Funktion behält alle Zeilen
Häufige Anwendungsfälle für GROUP BY
- Reporting-Dashboards — Summiere Gesamtwerte, Durchschnitte und Anzahlen nach Kategorie oder Zeitraum
- Headcount-Analyse — Zähle Mitarbeitende, Nutzer oder Datensätze nach Gruppe
- Umsatzaufschlüsselung — Gesamt- und Durchschnittsumsatz nach Produkt, Region oder Kunde
- Trendanalyse — Gruppiere nach Monat oder Jahr, um Muster im Zeitverlauf zu erkennen
- Top-N pro Gruppe — Kombiniere mit Subqueries oder CTEs, um die besten Performer in jeder Gruppe zu finden
- Datenvalidierung — Zähle Duplikate oder NULL-Werte über Gruppen hinweg
- Kohortenanalyse — Gruppiere Nutzer nach Anmeldedatum oder Verhaltenssegment
Performance-Tipps
- GROUP-BY-Spalten indexieren — Indizes auf gruppierten Spalten beschleunigen den Sortier- und Gruppierungsschritt
- Früh mit WHERE filtern — Zeilen vor dem Gruppieren mit WHERE zu reduzieren ist schneller, als sie danach mit HAVING zu filtern
- SELECT * vermeiden — Wähle nur die Spalten, die du wirklich brauchst; Aggregatoperationen profitieren von schmaleren Daten
- Covering-Indizes verwenden — Ein Index, der sowohl die GROUP-BY-Spalte als auch die aggregierte Spalte enthält, kann einen vollständigen Tabellenscan vermeiden
- Materialisierte Views in Betracht ziehen — Für häufig berechnete Aggregate auf großen Tabellen unterstützen einige Datenbanken vorkalkulierte Zusammenfassungen
Zusammenfassung
- GROUP BY fasst Zeilen, die dieselben Spaltenwerte haben, zu einer Zusammenfassungszeile pro eindeutiger Kombination zusammen
- COUNT(*) zählt alle Zeilen; COUNT(column) zählt Nicht-NULL-Werte; COUNT(DISTINCT column) zählt eindeutige Werte
- SUM summiert numerische Werte; AVG berechnet den Mittelwert; MIN / MAX finden die Grenzwerte
- Jede SELECT-Spalte muss entweder in GROUP BY erscheinen oder in eine Aggregatfunktion eingeschlossen sein
- WHERE filtert Zeilen vor dem Gruppieren; HAVING filtert Gruppen nach der Aggregation
- Du kannst nach Ausdrücken gruppieren (z. B.
SUBSTR(date, 1, 7)für Gruppierung auf Monatsebene) - Durch das Joinen von Tabellen vor dem Gruppieren kannst du Daten aus mehreren Quellen in einem Bericht kombinieren
- Verwende Window-Funktionen statt GROUP BY, wenn du Kennzahlen auf Gruppenebene brauchst, ohne einzelne Zeilen zu verlieren
Probiere aus, GROUP BY mit JOINs, CASE-Ausdrücken und HAVING-Klauseln zu kombinieren, um genau die Berichte zu erstellen, die deine Datenanalyse benötigt!