← CS Lab Databases & Data Modeling / SQL GROUP BY & Aggregation Open standalone ↗

GROUP BY collapses many rows into one row per group, and an aggregate function rolls each group up into a single value. It is how a table of individual records becomes a summary.

Where you meet it

What it does

Rows that share the same value in the grouping column fold together into one output row. For each group, an aggregate function reduces a column of many values down to one: COUNT, SUM, AVG, MIN, MAX. The grouping column survives; the individual detail rows do not.

WHERE filters rows before grouping, HAVING filters groups after — and only HAVING may test an aggregate.

How it works

The clauses run in a fixed order. WHERE filters rows before grouping. Then GROUP BY sorts the surviving rows into groups. The aggregate runs per group. Finally HAVING filters the groups after — and it is the only place an aggregate may be tested.

-- table: people(country, plan, spend)
SELECT   country,
         COUNT(*)     AS users,   -- one number per group
         SUM(spend)   AS total,
         AVG(spend)   AS avg_spend
FROM     people
WHERE    plan = 'Pro'             -- 1. drop rows first
GROUP BY country                  -- 2. fold rows into groups
HAVING   SUM(spend) > 500;        -- 3. keep only big-spending groups

Read it group by group: all Pro rows for DE become one row whose COUNT(*) is the row tally, SUM(spend) the total, AVG(spend) the mean — then the same for US, UK, and so on.

Watch out

  • No bare columns. Every column in SELECT must be in GROUP BY or wrapped in an aggregate. Standard SQL and PostgreSQL reject a stray column; MySQL 8 does too under ONLY_FULL_GROUP_BY (the default).
  • COUNT(*) vs COUNT(col). COUNT(*) counts rows; COUNT(col) counts only rows where col is not NULL. They differ whenever NULLs are present.
  • NULLs are skipped. SUM, AVG, MIN, MAX ignore NULL inputs — so AVG divides by the non-NULL count, not the row count.

Go deeper

GROUP BY verdichtet viele Zeilen zu einer Zeile pro Gruppe, und eine Aggregatfunktion rollt jede Gruppe zu einem einzigen Wert hoch. So wird aus einer Tabelle einzelner Datensätze eine Auswertung.

Wo es vorkommt

Was es tut

Zeilen mit gleichem Wert in der Gruppierungsspalte klappen zu einer Ausgabezeile zusammen. Für jede Gruppe reduziert eine Aggregatfunktion eine Spalte aus vielen Werten auf einen: COUNT, SUM, AVG, MIN, MAX. Der Gruppenschlüssel bleibt erhalten, die einzelnen Detailzeilen nicht.

WHERE filtert Zeilen vor dem Gruppieren, HAVING filtert Gruppen danach — und nur HAVING darf ein Aggregat prüfen.

Wie es funktioniert

Die Klauseln laufen in fester Reihenfolge. WHERE filtert Zeilen vor dem Gruppieren. Dann sortiert GROUP BY die übrigen Zeilen in Gruppen. Das Aggregat läuft pro Gruppe. Zuletzt filtert HAVING die Gruppen danach — und nur dort darf ein Aggregat geprüft werden.

-- Tabelle: people(country, plan, spend)
SELECT   country,
         COUNT(*)     AS users,   -- eine Zahl pro Gruppe
         SUM(spend)   AS total,
         AVG(spend)   AS avg_spend
FROM     people
WHERE    plan = 'Pro'             -- 1. erst Zeilen aussortieren
GROUP BY country                  -- 2. Zeilen in Gruppen falten
HAVING   SUM(spend) > 500;        -- 3. nur umsatzstarke Gruppen behalten

Lies es Gruppe für Gruppe: alle Pro-Zeilen für DE werden eine Zeile, deren COUNT(*) die Anzahl ist, SUM(spend) die Summe, AVG(spend) der Mittelwert — dann dasselbe für US, UK und so weiter.

Worauf achten

  • Keine nackten Spalten. Jede Spalte im SELECT muss im GROUP BY stehen oder in einem Aggregat sitzen. Standard-SQL und PostgreSQL lehnen eine freie Spalte ab; MySQL 8 ebenfalls unter ONLY_FULL_GROUP_BY (Default).
  • COUNT(*) vs. COUNT(col). COUNT(*) zählt Zeilen; COUNT(col) zählt nur Zeilen, in denen col nicht NULL ist. Bei NULL-Werten ergeben sie Unterschiedliches.
  • NULL wird übersprungen. SUM, AVG, MIN, MAX ignorieren NULL — AVG teilt also durch die Anzahl der Nicht-NULL-Werte, nicht durch die Zeilenzahl.

Mehr dazu

Next up
Databases & Data ModelingSQL JOINs Databases & Data ModelingSQL Window Functions All concepts →