What is the difference between WHERE and HAVING, and how does GROUP BY work?
GROUP BY collapses rows sharing a value into one row per group, so aggregate functions — COUNT, SUM, AVG, MIN, MAX — can be applied per group.
The difference between WHERE and HAVING is when they run:
- WHERE filters rows before grouping. It cannot reference an aggregate, because the aggregates do not exist yet.
- HAVING filters groups after aggregation. This is the only place you can filter on an aggregate value.
SELECT customer_id, COUNT(*) AS orders, SUM(amount) AS total
FROM orders
WHERE order_date >= '2026-01-01' -- filters rows first
GROUP BY customer_id
HAVING SUM(amount) > 50000 -- filters groups after
ORDER BY total DESC;The full logical order of execution — which explains most SQL confusion — is FROM and JOIN, then WHERE, then GROUP BY, then HAVING, then SELECT, then ORDER BY, then LIMIT. Because SELECT runs after HAVING, you generally cannot use a column alias in HAVING, though some databases permit it.
Note: Prefer WHERE for anything it can do, since filtering rows before grouping is cheaper than aggregating and discarding. And remember that COUNT(*) counts rows while COUNT(column) skips NULLs — a distinction that silently changes results.





