GROUP BY
GROUP BY
Section titled βGROUP BYβWhat it means
Section titled βWhat it meansβGROUP BY collapses rows sharing the same value(s) in specified column(s) into a single summary row per group, typically paired with aggregate functions (COUNT, SUM, AVG, etc.). HAVING filters after grouping (on aggregated values), while WHERE filters before grouping (on individual rows).
Examples
Section titled βExamplesβSELECT CustomerId, COUNT(*) AS order_count, SUM(Amount) AS total_spentFROM OrdersGROUP BY CustomerId;
-- Group by multiple columnsSELECT CustomerId, YEAR(OrderDate) AS order_year, SUM(Amount) AS yearly_totalFROM OrdersGROUP BY CustomerId, YEAR(OrderDate);
-- Filter groups with HAVING (after aggregation)SELECT CustomerId, SUM(Amount) AS total_spentFROM OrdersGROUP BY CustomerIdHAVING SUM(Amount) > 1000;
-- WHERE filters rows BEFORE grouping; HAVING filters groups AFTERSELECT CustomerId, COUNT(*) AS order_countFROM OrdersWHERE OrderDate >= '2026-01-01'GROUP BY CustomerIdHAVING COUNT(*) > 5;Common mistake
Section titled βCommon mistakeβUsing WHERE to filter on an aggregate value β WHERE runs before grouping happens, so it has no access to aggregated results like SUM(Amount); thatβs exactly what HAVING is for.
-- Error: Invalid column name / aggregate not allowed in WHERESELECT CustomerId, SUM(Amount)FROM OrdersWHERE SUM(Amount) > 1000GROUP BY CustomerId;
-- Correct: use HAVING to filter on the aggregated resultSELECT CustomerId, SUM(Amount)FROM OrdersGROUP BY CustomerIdHAVING SUM(Amount) > 1000;Quick practice
Section titled βQuick practiceβ-
Whatβs the difference between
WHEREandHAVING?Answer
WHEREfilters individual rows before grouping/aggregation happens;HAVINGfilters entire groups after aggregation, and can reference aggregate functions likeSUM(). -
What does
GROUP BY CustomerId, YEAR(OrderDate)produce?Answer
One summary row per unique combination of customer and order year β not one row per customer overall. -
Can
WHEREreference an aggregate function likeCOUNT(*)?Answer
No β aggregates aren't computed yet whenWHEREruns; useHAVINGinstead to filter on aggregated values.