WHERE, GROUP BY, HAVING – Quick Guide
Core ideas
- WHERE filters rows.
- GROUP BY makes groups of rows.
- HAVING filters groups (after grouping).
- 👉 Rule that never changes:Every column in
SELECTmust be either:- in
GROUP BY, or - an aggregate (
SUM,COUNT,AVG,MAX,MIN).
- in
- Execution order (simplified):
FROM / JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY (→ LIMIT/OFFSET if supported)
WHERE vs HAVING
| WHERE | HAVING |
|---|---|
| Filters rows | Filters groups |
| Used before GROUP BY | Used after GROUP BY |
| Cannot use aggregates | Can use aggregates |
- WHERE filters rows (pre-aggregation).
- HAVING filters groups (post-aggregation).
- Prefer WHERE when possible (filters earlier, usually faster); use HAVING when you need to filter on aggregates.
Example using both together
Goal: Customers whose individual order is ≥ 100 and total spent > 250.
| |
Sample table to imagine
| |
1️⃣ GROUP BY – “make groups”
Question: Total amount spent by each customer
| |
What happens:
- Rows are grouped by
customer. SUM(amount)is calculated per group.
Result:
| customer | total_amount |
|---|---|
| A | 300 |
| B | 200 |
| C | 300 |
Rule to remember
Every column in
SELECTmust be either
- in
GROUP BY, or- an aggregate (
SUM,COUNT,AVG,MAX,MIN).
2️⃣ HAVING – “filter the groups”
Question: Show only customers whose total amount is greater than 250
❌ Wrong (common mistake):
| |
- This fails because WHERE runs before grouping, so aggregates are not available there.
✅ Correct:
| |
| |
- HAVING works after GROUP BY, so it can use aggregates like
SUM(amount).
Common questions
Q1: Can we use HAVING without GROUP BY?
✔️ Yes (but uncommon):
| |
- Without
GROUP BY, all rows form one implicit group, andHAVINGfilters that single aggregated result.
Q2: Can we use WHERE with GROUP BY?
✔️ Yes — and often together.
- Use WHERE to filter raw rows before grouping.
- Use HAVING to filter on aggregate results after grouping.
Q3: Why can’t we use aggregate functions in WHERE?
Because WHERE executes before GROUP BY, so aggregate values like SUM(amount) or COUNT(*) do not exist yet at that stage.