HAVING Clause
Filter groups after aggregation
HAVING filters groups after aggregation. It's like WHERE, but for aggregate results.
WHERE vs HAVING
| WHERE | HAVING |
|---|---|
| Filters individual rows | Filters grouped results |
| Runs before GROUP BY | Runs after GROUP BY |
| Can't use aggregates | Can use aggregates |
Basic HAVING
-- Countries with more than 100 users SELECT country, COUNT(*) AS user_count FROM users GROUP BY country HAVING COUNT(*) > 100; -- Customers who spent over $1000 SELECT user_id, SUM(total) AS total_spent FROM orders GROUP BY user_id HAVING SUM(total) > 1000;
WHERE + HAVING Together
-- Active customers with 5+ orders in 2024
SELECT
user_id,
COUNT(*) AS order_count,
SUM(total) AS total_spent
FROM orders
WHERE status = 'completed' -- Filter rows FIRST
AND created_at >= '2024-01-01'
GROUP BY user_id
HAVING COUNT(*) >= 5 -- Filter groups AFTER
ORDER BY total_spent DESC;Execution Order
- 1. FROM / JOIN
- 2. WHERE (filter rows)
- 3. GROUP BY (create groups)
- 4. HAVING (filter groups)
- 5. SELECT (compute columns)
- 6. ORDER BY (sort results)
- 7. LIMIT (restrict output)