GROUP BY and HAVING are two of the most misunderstood SQL clauses. Many beginners mix them up or don't know when to use each. This guide will clear up the confusion permanently.
GROUP BY collapses multiple rows into a single summary row per group. Every column in SELECT must either be in GROUP BY or wrapped in an aggregate function.
SELECT department, COUNT(*) AS headcount, ROUND(AVG(salary), 0) AS avg_salary FROM employees GROUP BY department ORDER BY avg_salary DESC;
HAVING filters groups AFTER GROUP BY has run. Think of it as WHERE for aggregate results. You cannot use WHERE to filter on COUNT(*) — you must use HAVING.
SELECT department, COUNT(*) AS headcount FROM employees GROUP BY department HAVING COUNT(*) > 10 ORDER BY headcount DESC; -- Only departments with more than 10 employees
WHERE runs BEFORE aggregation (filters rows). HAVING runs AFTER aggregation (filters groups). You can use both in the same query.
Run all the queries from this article in our free SQL playground.
Open SQL Playground →