GROUP BY vs HAVING đź§®
Where you filter decides whether it works.
Both filter rows, but at different stages. Mix them up and your query errors out — or silently lies.
WHERE filters rows, HAVING filters groups
- WHERE runs before grouping. It cannot see aggregates like
COUNT()orSUM(). - GROUP BY collapses rows into groups.
- HAVING runs after grouping. It filters those groups using aggregates.
Think of it as a pipeline: WHERE → GROUP BY → HAVING.
Example
Find customers who placed more than 3 orders in 2025:
SELECT customer_id, COUNT(*) AS order_count
FROM orders
WHERE order_date >= '2025-01-01' -- filter rows first
GROUP BY customer_id
HAVING COUNT(*) > 3 -- then filter groups
ORDER BY order_count DESC;WHERE order_date >= ... trims raw rows cheaply. HAVING COUNT(*) > 3 can only happen after the rows are grouped, because the count doesn't exist until then.
Rule of thumb
If your filter mentions an aggregate, it belongs in HAVING. If it only mentions plain columns, use WHERE — it's faster because fewer rows reach the grouping step.
Get Marcelo Domingues’s stories in your inbox
Join Medium for free to get updates from this writer.
TL;DR: WHERE filters individual rows before grouping; HAVING filters aggregated groups after.
👉 Next query, ask: “Am I filtering a row or a group?”







