The distinction
WHERE filters rows before grouping. HAVING filters groups after aggregation.
SELECT region, SUM(total) AS revenue
FROM orders
WHERE order_date >= '2024-01-01' -- rows first
GROUP BY region
HAVING SUM(total) > 100000; -- then groupsWhich to use
If the condition is on a raw column value, it belongs in WHERE. If it is on an aggregate, it must go in HAVING.
Putting a row-level condition in HAVING usually still works but is slower — more rows reach the grouping step only to be discarded afterwards.
HAVING without GROUP BY
Legal, if unusual. The whole table is treated as one group:
SELECT SUM(total) FROM orders HAVING SUM(total) > 1000000;
Returns the total, or no rows at all if it fails the test.
Aliases in HAVING
Most dialects require you to repeat the aggregate expression rather than referencing the SELECT alias, because HAVING is evaluated before SELECT. MySQL and Postgres are more permissive, but repeating it is portable.