GROUP BY
SUM and COUNT get far more useful once you can apply them separately to different subsets of rows — total sales per region, order count per customer, average score per class. GROUP BY is what makes that possible.Grouping rows that share a value
GROUP BY collapses all rows that share the same value in a given column into a single output row, and lets you run aggregate functions across each of those groups independently:
Total sales per department
SELECT department, SUM(amount) AS total_sales FROM sales GROUP BY department;
department | total_sales -------------+------------- Engineering | 48000 Sales | 92000 Marketing | 31000
department value.The rule: SELECT columns must be grouped or aggregated
Error — employee_name is not grouped or aggregated
-- This raises an error in PostgreSQL, MySQL (in strict mode), and SQL Server SELECT department, employee_name, SUM(amount) FROM sales GROUP BY department;
Fixed — group by both columns, or aggregate employee_name
-- Option 1: group by both columns SELECT department, employee_name, SUM(amount) FROM sales GROUP BY department, employee_name; -- Option 2: aggregate employee_name instead (e.g. count how many contributed) SELECT department, COUNT(DISTINCT employee_name) AS contributors, SUM(amount) FROM sales GROUP BY department;
Grouping by multiple columns
Sales per department, per quarter
SELECT department, quarter, SUM(amount) AS total_sales FROM sales GROUP BY department, quarter ORDER BY department, quarter;
Logical execution order
It helps to know that GROUP BY runs after WHERE but before ORDER BY and before the final SELECT columns are computed. Conceptually:
FROM — read the source table(s), applying any joins
WHERE — filter individual rows, before any grouping happens
GROUP BY — collapse the remaining rows into groups
HAVING — filter entire groups (covered next)
SELECT — compute the output columns and aggregates
ORDER BY — sort the final result
GROUP BY collapses rows sharing the same value(s) into one row per group
Any SELECT column that isn't aggregated must appear in GROUP BY
You can group by multiple columns to get one row per unique combination
WHERE filters rows before grouping; HAVING filters entire groups after grouping