Skip to main content

HAVING Clause

HAVING is for filtering groups, not raw rows. Think of it as WHERE for aggregate output.

WHERE vs HAVING​

ClauseEvaluated onTypical use
WHERERaw rows before groupingWHERE status = 'paid'
HAVINGGrouped rows after aggregationHAVING SUM(total_amount) > 10000

Core Syntax​

SELECT customer_id, SUM(total_amount) AS total_spend
FROM orders
WHERE order_date >= '2026-01-01'
GROUP BY customer_id
HAVING total_spend >= 5000;

Practical Example​

Active High-Value Customers​

SELECT customer_id,
COUNT(*) AS order_count,
SUM(total_amount) AS total_spend
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
HAVING COUNT(*) >= 5
AND SUM(total_amount) >= 10000
ORDER BY total_spend DESC;
customer_idorder_counttotal_spend
10241124300.00
2031713120.00
4120610205.00

Common Pitfalls​

PitfallConsequencePrevention
Using aggregate in WHERESyntax errorMove aggregate predicates to HAVING
Putting non-aggregate filters in HAVING onlyUnnecessary processingKeep row filters in WHERE, group filters in HAVING
Forgetting aliases in long expressionsHard-to-read queriesAlias aggregates and reuse aliases in HAVING (MySQL allows it)

Quick Reference​

SELECT k, COUNT(*) c FROM t GROUP BY k HAVING c > 10;
SELECT k, SUM(v) s FROM t WHERE status = 'ok' GROUP BY k HAVING s >= 1000;
SELECT k, AVG(score) a FROM t GROUP BY k HAVING a BETWEEN 70 AND 90;

What's Next​