intermediate
HAVING
Filter groups after aggregation — the GROUP BY equivalent of WHERE.
5 min read
Explanation
WHERE filters rows before they are grouped. But what if you want to keep
only the groups that meet a condition — for example, categories that contain
more than three products?
That is exactly what HAVING is for. It filters groups after GROUP BY
has done its work, so it can test aggregate values like COUNT(*) or
SUM(price).
The mental model:
WHEREremoves rows you don't want.GROUP BYgroups what remains.- Aggregates compute one value per group.
HAVINGkeeps only the groups that pass its test.
Syntax
SELECT column, AGGREGATE(col)
FROM table_name
GROUP BY column
HAVING AGGREGATE(col) > some_value;Interactive Example
Show only categories that have more than three products. Then show categories whose average price is above 50.
Loading database engine...
Loading database engine...
Common Mistakes
- Using
WHEREto test an aggregate.WHERE COUNT(*) > 3is invalid — aggregates aren't available yet. UseHAVING. - Forgetting the
GROUP BY.HAVINGwithout grouping usually makes no sense; it filters the single whole-table group. - Confusing the two filter points. Remember:
WHERE→ rows in,HAVING→ groups out.
Best Practices
- Apply row-level filters in
WHEREfirst (it's cheaper), then group, then useHAVINGonly for aggregate conditions. - You can reuse the same aggregate in
HAVINGthat you used inSELECT. - Aliases defined in
SELECTare not portable toHAVINGin every database, so repeating the aggregate expression is the safest habit.
Practice Question
Using products, return each category with its total stock, but only for
categories whose total stock is greater than 400.
Summary
HAVING filters grouped rows using aggregate conditions that WHERE cannot
express. The pipeline is WHERE → GROUP BY → aggregates → HAVING →
ORDER BY.