What is the difference between WHERE and HAVING in SQL?
WHERE filters individual rows before any grouping or aggregation occurs; HAVING filters groups after aggregation. You cannot reference an aggregate function like COUNT() or SUM() in a WHERE clause because those values don't exist yet at that stage of query execution.
How to think about it
WHERE and HAVING both filter, but at completely different stages of execution — and the whole answer is the logical processing order:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
WHERE runs at step 2, before any groups exist, so an aggregate like COUNT(*) is meaningless there. HAVING runs at step 4, after grouping, when aggregates are fully computed. That’s why one filters rows and the other filters groups.
A worked example — both clauses, one query
Find customers with more than 5 orders in 2024. WHERE drops non-2024 rows early; HAVING then judges the aggregated groups:
SELECT customer_id,
COUNT(*) AS orders_in_2024,
SUM(amount) AS total_spent
FROM orders
WHERE order_year = 2024 -- step 2: per-row, before grouping
GROUP BY customer_id
HAVING COUNT(*) > 5 -- step 4: per-group, after aggregation
ORDER BY total_spent DESC;
| customer_id | orders_in_2024 | total_spent |
|---|---|---|
| 3 | 6 | 465 |
Only customer 3 survives. Trace it: WHERE order_year = 2024 first removes customer 1’s lone 2023 order, leaving customer 1 with four 2024 orders, customer 2 with two, and customer 3 with six. After GROUP BY, HAVING COUNT(*) > 5 keeps only the group of six. The division of labour is the point — WHERE shrinks the rows cheaply before the aggregation work, HAVING filters the much smaller set of groups after.
HAVING can even run without GROUP BY, treating the whole table as one group: SELECT COUNT(*) FROM orders HAVING COUNT(*) > 1000 returns the count only if there are more than 1,000 orders. Valid, if unusual.