The HAVING clause filters the results after GROUP BY has formed its groups. It is the equivalent of WHERE, but for grouped data. While WHERE cannot reference aggregate functions like COUNT() or SUM(), HAVING can — because by the time HAVING runs, the groups and their aggregates have already been calculated.
| Clause | Filters | Can use aggregate functions? |
|---|---|---|
WHERE |
Individual rows before grouping | No |
HAVING |
Groups after grouping | Yes |
SELECT column, aggregate_function(column)
FROM table_name
WHERE condition
GROUP BY column
HAVING aggregate_condition
ORDER BY column;
| id | name | category | price | quantity_sold |
|---|---|---|---|---|
| 1 | Laptop | Electronics | 55000.00 | 5 |
| 2 | Phone | Electronics | 25000.00 | 12 |
| 3 | T-Shirt | Clothing | 800.00 | 40 |
| 4 | Headphones | Electronics | 3500.00 | 18 |
| 5 | Jeans | Clothing | 2200.00 | 22 |
| 6 | Tablet | Electronics | 35000.00 | 8 |
| 7 | Jacket | Clothing | 4500.00 | 15 |
Show only categories that contain more than 3 products:
SELECT category, COUNT(*) AS total
FROM products
GROUP BY category
HAVING COUNT(*) > 3;
| category | total |
|---|---|
| Electronics | 4 |
Clothing has only 3 products, so it is excluded. Electronics has 4 and passes the filter.
Show only categories where the total units sold exceed 50:
SELECT category, SUM(quantity_sold) AS total_sold
FROM products
GROUP BY category
HAVING SUM(quantity_sold) > 50;
| category | total_sold |
|---|---|
| Clothing | 77 |
Find categories where the average price is above 10,000:
SELECT category, ROUND(AVG(price), 2) AS avg_price
FROM products
GROUP BY category
HAVING AVG(price) > 10000;
| category | avg_price |
|---|---|
| Electronics | 29625.00 |
Use both in the same query: WHERE filters individual rows first, then GROUP BY forms groups, and finally HAVING filters those groups:
-- Among products priced above 1000 only,
-- show categories with more than 2 such products
SELECT category, COUNT(*) AS total
FROM products
WHERE price > 1000
GROUP BY category
HAVING COUNT(*) > 2;
WHERE → GROUP BY → HAVING → ORDER BY → LIMIT.
WHERE filters rows before grouping; HAVING filters groups after.
You can combine multiple conditions in HAVING using AND and OR:
-- Categories with more than 2 products AND average price above 5000
SELECT category, COUNT(*) AS total, ROUND(AVG(price), 2) AS avg_price
FROM products
GROUP BY category
HAVING COUNT(*) > 2 AND AVG(price) > 5000;
HAVING filters groups after GROUP BY — it is the post-grouping equivalent of WHERE.WHERE cannot use aggregate functions; HAVING can.WHERE and HAVING in the same query — they serve different stages.WHERE (rows) → GROUP BY (groups) → HAVING (filter groups) → ORDER BY.HAVING using AND and OR.