WHERE vs HAVING
WHERE filters rows before they are grouped; HAVING filters groups after aggregation, so it can use COUNT, SUM and other aggregates.
FormulaWHERE filters rows before GROUP BY · HAVING filters groups after
How we work it through
- 1
Row conditions (status, date) go in WHERE.
- 2
Conditions on aggregates (COUNT, SUM) go in HAVING.
- 3
Read the query in execution order: FROM → WHERE → GROUP BY → HAVING → SELECT.
On the practice dataset
The query we run on Meridian, Atterna’s practice marketplace, and what it returns.
SELECT buyer_id, COUNT(*) AS paid_orders
FROM meridian.orders
WHERE status = 'paid' -- rows
GROUP BY buyer_id
HAVING COUNT(*) >= 3; -- groupsResult1,475 buyers with three or more paid orders
The common trap
Putting a row condition in HAVING (an error for a column that isn’t grouped, wasted work for one that is), or an aggregate in WHERE (always an error).
When an AI answers
“SELECT buyer_id FROM orders GROUP BY buyer_id HAVING status = 'paid' AND COUNT(*) >= 3”
- What it didn’t know
- It put a row condition in HAVING; the database rejects it or it filters the wrong thing.
- Ask back
- “Move status = 'paid' to WHERE so it applies before grouping.”
Read next
Examples use Meridian, Atterna’s fictional practice marketplace.