GROUP BY in SQL: Gruppierungen und Aggregatfunktionen
Die GROUP BY-Klausel ist das zentrale Werkzeug, wenn du in SQL Daten nicht nur abrufen, sondern sinnvoll zusammenfassen willst. Sie gruppiert Zeilen mit identischen Werten in einer oder mehreren Spalten zu einer einzigen Zusammenfassungszeile. Das Ergebnis: statt tausend Einzelzeilen siehst du zum Beispiel den Gesamtumsatz pro Abteilung oder die Anzahl der Bestellungen pro Kunde.
Ohne GROUP BY liefern Aggregatfunktionen wie SUM(), COUNT(), AVG(), MIN() und MAX() immer nur einen einzigen Wert für die gesamte Tabelle. Erst in Kombination mit der Gruppierungsklausel entfalten sie ihre eigentliche Stärke: einen Wert pro Gruppe.
Kurz zusammengefasst, was GROUP BY leistet:
- Fasst Zeilen mit gleichen Spaltenwerten zu einer Gruppe zusammen
- Ermöglicht Aggregationen wie Summen, Durchschnitte und Zählungen pro Gruppe
- Arbeitet eng mit SUM(), COUNT(), AVG(), MIN() und MAX() zusammen
- Bildet die Grundlage für gruppierte Berichte und Datenanalysen
- Wird durch HAVING gefiltert und durch ORDER BY sortiert
Inhaltsverzeichnis
- Wie funktioniert GROUP BY in SQL? Syntax und Grundprinzip
- Welche Aggregatfunktionen lassen sich mit GROUP BY kombinieren?
- WHERE oder HAVING? Wann welche Klausel filtert
- Wie du Ergebnisse nach einer Gruppierung sinnvoll sortierst
- Wie du nach mehreren Spalten gleichzeitig gruppierst
- Häufige Fehler bei GROUP BY und wie du sie vermeidest
- GROUP BY in Verbindung mit JOIN-Abfragen
- Wie sich GROUP BY auf die Abfrageleistung auswirkt
- Was ist der Unterschied zwischen GROUP BY und DISTINCT?
- Was GROUP BY in verschiedenen SQL-Dialekten einschränkt
- Wichtige Erkenntnisse
- FAQ
Wie funktioniert GROUP BY in SQL? Syntax und Grundprinzip
Die Grundsyntax ist überschaubar:
SELECT spalte1, aggregatfunktion(spalte2)
FROM tabellenname
WHERE bedingung
GROUP BY spalte1;
Die Reihenfolge der Klauseln ist dabei nicht verhandelbar: WHERE kommt vor GROUP BY, und HAVING folgt danach. Wer diese Reihenfolge durcheinanderbringt, bekommt einen Syntaxfehler.
Ein einfaches Beispiel: Du willst den Gesamtumsatz pro Abteilung aus einer Tabelle Mitarbeiter ermitteln.
SELECT Abteilung, SUM(Gehalt) AS Gesamtgehalt
FROM Mitarbeiter
GROUP BY Abteilung;
SQL liest alle Zeilen, bildet für jeden eindeutigen Wert in Abteilung eine Gruppe und berechnet dann SUM(Gehalt) innerhalb jeder Gruppe. Das Ergebnis hat genau so viele Zeilen, wie es unterschiedliche Abteilungen gibt.
Profi-Tipp: Moderne Datenbanksysteme wie MySQL ab Version 5.7 erzwingen den Modus ONLY_FULL_GROUP_BY. Das bedeutet: Jede Spalte im SELECT, die keine Aggregatfunktion ist, muss auch in der GROUP BY-Liste stehen. Wer das ignoriert, bekommt einen Fehler statt eines falschen Ergebnisses. Das ist gut so. *Welche Aggregatfunktionen lassen sich mit GROUP BY kombinieren?
Die fünf wichtigsten SQL-Aggregatfunktionen im Überblick:
| Funktion | Beschreibung |
| SUM(spalte) | Addiert alle Werte einer Spalte innerhalb der Gruppe |
| AVG(spalte) | Berechnet den Durchschnitt, ignoriert dabei NULL-Werte |
| COUNT(*) | Zählt alle Zeilen einer Gruppe, auch solche mit NULL |
| COUNT(spalte) | Zählt nur Zeilen, bei denen die Spalte nicht NULL ist |
| MIN(spalte) / MAX(spalte) | Gibt den kleinsten bzw. größten Wert zurück |
Praktisches Beispiel mit mehreren Funktionen auf einmal:
SELECT Kategorie,
COUNT(*) AS Anzahl,
SUM(Preis) AS Gesamtpreis,
AVG(Preis) AS Durchschnittspreis,
MIN(Preis) AS Guenstigster,
MAX(Preis) AS Teuerster
FROM Produkte
GROUP BY Kategorie;
Wer die Logik hinter MIN() und MAX() erst mit Excel geübt hat, findet den Übergang zu SQL deutlich leichter. Logicexcel bietet dafür kostenlose Übungen zu MIN und MAX direkt im Browser an.
Ein wichtiger Punkt zu AVG(): Die Funktion ignoriert NULL-Werte automatisch. Wenn von zehn Zeilen drei keinen Wert haben, berechnet AVG() den Durchschnitt aus den verbleibenden sieben. Das kann das Ergebnis erheblich verzerren, wenn NULL eigentlich für „0“ steht.
*WHERE oder HAVING? Wann welche Klausel filtert
Der Unterschied ist konzeptionell einfach, wird aber ständig verwechselt. WHERE filtert einzelne Zeilen vor der Gruppierung. HAVING filtert ganze Gruppen nach der Aggregation.
-- Nur Mitarbeiter mit Gehalt über 3000 berücksichtigen,
-- dann Abteilungen mit mehr als 5 Mitarbeitern anzeigen
SELECT Abteilung, COUNT(*) AS Anzahl
FROM Mitarbeiter
WHERE Gehalt > 3000
GROUP BY Abteilung
HAVING COUNT(*) > 5;
Aggregate können in WHERE nicht verwendet werden, weil die Aggregation zu diesem Zeitpunkt noch nicht stattgefunden hat. WHERE SUM(Gehalt) > 10000 wirft einen Fehler. Dafür ist HAVING zuständig.
> Faustregel: WHERE arbeitet auf Zeilenebene, HAVING auf Gruppenebene. Wenn du eine Bedingung auf ein Aggregat stellst, gehört sie immer in HAVING.
Typischer Fehler: Entwickler schreiben WHERE COUNT() > 5 und wundern sich über den Fehler. Die Lösung ist schlicht, HAVING COUNT() > 5 zu schreiben.
*Wie du Ergebnisse nach einer Gruppierung sinnvoll sortierst
GROUP BY selbst sortiert nichts. Die Reihenfolge der Ausgabe ist ohne explizite Sortierung nicht garantiert. Wer die Ergebnisse geordnet haben will, hängt ORDER BY ans Ende der Abfrage.SELECT Abteilung, SUM(Gehalt) AS Gesamtgehalt
FROM Mitarbeiter
GROUP BY Abteilung
ORDER BY Gesamtgehalt DESC;
ASC (aufsteigend) ist der Standard und muss nicht angegeben werden. DESC dreht die Reihenfolge um. Du kannst nach der Gruppierungsspalte selbst oder nach dem Aggregatwert sortieren. Beides ist erlaubt.
Praktisch: Wenn du die Top-5-Kategorien nach Umsatz willst, kombinierst du ORDER BY SUM(Preis) DESC mit LIMIT 5 (MySQL/PostgreSQL) oder TOP 5 (SQL Server).
*Wie du nach mehreren Spalten gleichzeitig gruppierst
Manchmal reicht eine Spalte nicht. Wenn du den Umsatz nicht nur pro Jahr, sondern pro Jahr und Abteilung willst, gibst du beide Spalten in GROUP BY an.
SELECT Jahr, Abteilung, SUM(Umsatz) AS Gesamtumsatz
FROM Verkaufsdaten
GROUP BY Jahr, Abteilung
ORDER BY Jahr, Abteilung;
SQL bildet dann eine Gruppe für jede eindeutige Kombination aus Jahr und Abteilung. Aus drei Jahren und vier Abteilungen entstehen bis zu zwölf Gruppen. Die Reihenfolge der Spalten in GROUP BY beeinflusst das Ergebnis nicht, wohl aber die Lesbarkeit.
Für mehrdimensionale Berichte, etwa Umsatz nach Region und Quartal, ist diese Technik unverzichtbar. Wer tiefer in die Datenanalyse einsteigen will, findet beim Datenbankmanagement-Kurs strukturierte Weiterbildung dazu.
*Häufige Fehler bei GROUP BY und wie du sie vermeidest
Der häufigste Fehler: Eine Spalte im SELECT angeben, die weder in GROUP BY noch in einer Aggregatfunktion steht. Datenbanken mit aktiviertem ONLY_FULL_GROUP_BY werfen dafür sofort einen Fehler.
-- FALSCH: Name ist nicht in GROUP BY
SELECT Abteilung, Name, SUM(Gehalt)
FROM Mitarbeiter
GROUP BY Abteilung;
-- RICHTIG:
SELECT Abteilung, SUM(Gehalt)
FROM Mitarbeiter
GROUP BY Abteilung;
Weitere typische Stolpersteine:
- NULL-Werte in Gruppierungsspalten: SQL behandelt alle NULL-Werte als gleichwertig und fasst sie in eine gemeinsame Gruppe zusammen. Das kann zu überraschend großen „unbekannt“-Gruppen führen.
- COUNT(*) vs. COUNT(spalte) verwechseln: Wer Zeilen mit NULL ausschließen will, muss COUNT(spalte) verwenden.
- HAVING statt WHERE vergessen: Bedingungen auf Aggregate gehören in HAVING, nicht in WHERE.
Für erweiterte Analysen bieten ROLLUP, CUBE und GROUPING SETS mächtige Erweiterungen. ROLLUP erzeugt hierarchische Zwischensummen, CUBE alle möglichen Kombinationen, GROUPING SETS genau die Kombinationen, die du angibst. Alle drei ersetzen mehrere separate Abfragen durch eine einzige.
-- ROLLUP: Gesamtsumme und Zwischensummen pro Jahr
SELECT Jahr, Abteilung, SUM(Umsatz)
FROM Verkaufsdaten
GROUP BY ROLLUP(Jahr, Abteilung);
*
GROUP BY in Verbindung mit JOIN-Abfragen
GROUP BY und JOIN ergänzen sich hervorragend. Oft liegen die Daten, die du aggregieren willst, in mehreren Tabellen verteilt.SELECT k.Name, COUNT(b.BestellID) AS Bestellungen
FROM Kunden k
JOIN Bestellungen b ON k.KundenID = b.KundenID
GROUP BY k.KundenID, k.Name
ORDER BY Bestellungen DESC;
Hier verbindet der JOIN die Kundentabelle mit der Bestelltabelle. GROUP BY fasst dann alle Bestellungen pro Kunde zusammen, COUNT() zählt sie. Wichtig: Wenn du nach k.Name gruppierst, solltest du auch k.KundenID in GROUP BY aufnehmen, falls zwei Kunden denselben Namen haben könnten.
Bei LEFT JOIN entstehen für Kunden ohne Bestellungen Zeilen mit NULL in den Bestellspalten. COUNT(b.BestellID) gibt dann 0 zurück, COUNT(*) würde 1 zurückgeben. Das ist ein klassischer Fall, wo die Wahl zwischen beiden COUNT-Varianten das Ergebnis verändert.
*Wie sich GROUP BY auf die Abfrageleistung auswirkt
Gruppierungsabfragen auf großen Tabellen können langsam werden. Ein Index auf der Gruppierungsspalte hilft dem Datenbanksystem, die Zeilen schneller zu sortieren und zusammenzufassen.
Konkrete Hinweise:
- Index auf GROUP BY-Spalten setzen: Besonders bei häufig genutzten Gruppierungsspalten wie Abteilung oder Datum lohnt sich ein Index.
- Filtern vor dem Gruppieren: Ein enger WHERE-Filter reduziert die Datenmenge, bevor GROUP BY ansetzt. Weniger Zeilen bedeuten weniger Rechenaufwand.
- HAVING sparsam einsetzen: HAVING filtert erst nach der Aggregation. Was sich als WHERE-Bedingung formulieren lässt, sollte dort stehen.
- Spaltenanzahl begrenzen: Nur die Spalten in SELECT aufnehmen, die tatsächlich gebraucht werden.
Was ist der Unterschied zwischen GROUP BY und DISTINCT?
Beide entfernen Duplikate, aber auf unterschiedliche Weise. DISTINCT gibt eindeutige Zeilen zurück, ohne zu aggregieren. GROUP BY fasst Zeilen zusammen und erlaubt dabei Berechnungen.
-- Gibt alle eindeutigen Abteilungen zurück
SELECT DISTINCT Abteilung FROM Mitarbeiter;
-- Gibt Abteilungen mit Mitarbeiterzahl zurück
SELECT Abteilung, COUNT(*) FROM Mitarbeiter GROUP BY Abteilung;
Wenn du nur wissen willst, welche Werte existieren, reicht DISTINCT. Sobald du etwas berechnen willst, brauchst du GROUP BY. In manchen Datenbanken erzeugt SELECT DISTINCT spalte intern denselben Ausführungsplan wie GROUP BY spalte, aber semantisch sind sie verschieden.
*Was GROUP BY in verschiedenen SQL-Dialekten einschränkt
Die SQL-Norm definiert GROUP BY, aber jede Datenbank setzt eigene Grenzen:
- MySQL erlaubt ohne ONLY_FULL_GROUP_BY nicht aggregierte Spalten im SELECT, was zu zufälligen Ergebnissen führen kann. Ab MySQL 5.7 ist der Modus standardmäßig aktiv.
- SQLite ist großzügiger: Es erlaubt „bare columns“ im SELECT, also Spalten, die weder in GROUP BY noch in einer Aggregatfunktion stehen. Der zurückgegebene Wert ist dann ein beliebiger Wert aus der Gruppe.
- SQL Server und PostgreSQL erzwingen strikte Konformität: Jede nicht aggregierte Spalte muss in GROUP BY stehen.
- ROLLUP und CUBE sind in SQL Server und PostgreSQL vollständig implementiert, in SQLite nicht verfügbar.
- Die maximale Anzahl an Ausdrücken in einer GROUP BY-Klausel ist in SQL Server auf 4.096 Gruppen begrenzt.
SQL-Wissen durch Übung festigen: Theorie allein reicht nicht. Logicexcel bietet kostenlose SQL-Übungen zum direkten Ausprobieren, mit sofortigem Feedback und ohne Registrierung. Ideal, um GROUP BY, Aggregatfunktionen und HAVING wirklich zu verinnerlichen.
*
Wichtige Erkenntnisse
Die GROUP BY-Klausel ist das Fundament jeder aggregierten SQL-Abfrage: Wer sie beherrscht, kann aus rohen Tabellendaten aussagekräftige Berichte erstellen.
| Thema | Details |
| Grundprinzip von GROUP BY | Fasst Zeilen mit identischen Spaltenwerten zusammen und ermöglicht Aggregationen pro Gruppe. |
| WHERE vs. HAVING | WHERE filtert vor der Gruppierung auf Zeilenebene, HAVING danach auf Gruppenebene. |
| NULL-Behandlung | Alle NULL-Werte in einer Gruppierungsspalte landen in einer gemeinsamen Gruppe. |
| COUNT() vs. COUNT(spalte) | COUNT() zählt alle Zeilen, COUNT(spalte) ignoriert Zeilen mit NULL in der Spalte. |
| Erweiterte Gruppierungen | ROLLUP, CUBE und GROUPING SETS ermöglichen mehrdimensionale Auswertungen in einer einzigen Abfrage. |
FAQ
Wann benutzt man GROUP BY in SQL?
GROUP BY kommt immer dann zum Einsatz, wenn du Daten nach einem gemeinsamen Merkmal zusammenfassen und darauf eine Berechnung anwenden willst, zum Beispiel den Umsatz pro Monat oder die Anzahl der Bestellungen pro Kunde.Was ist der Unterschied zwischen GROUP BY und ORDER BY?
GROUP BY fasst Zeilen mit gleichen Werten zu Gruppen zusammen und ermöglicht Aggregationen. ORDER BY sortiert lediglich die Ausgabe und verändert die Daten selbst nicht.Was macht HAVING in einer GROUP BY-Abfrage?
HAVING filtert die Ergebnisse nach der Gruppierung auf Basis von Aggregatwerten. Im Gegensatz zu WHERE, das vor der Gruppierung auf einzelne Zeilen wirkt, kann HAVING Bedingungen wie HAVING COUNT(*) > 5 auf ganze Gruppen anwenden.Wie verwendet man GROUP BY mit mehreren Spalten?
Du listest einfach alle gewünschten Spalten kommagetrennt in der GROUP BY-Klausel auf, zum Beispiel GROUP BY Jahr, Abteilung. SQL bildet dann eine Gruppe für jede eindeutige Kombination dieser Spaltenwerte.
Was passiert mit NULL-Werten in GROUP BY?
SQL behandelt alle NULL-Werte in einer Gruppierungsspalte als gleichwertig und fasst sie in eine einzige Gruppe zusammen. Das kann zu einer unerwartet großen Gruppe führen, wenn viele Zeilen keinen Wert in der Gruppierungsspalte haben.