CodeMIRAI
0 XP

HAVING

2 min read 5 runnable examples Quiz included

WHERE filters rows. But "which categories have at least two products?" is a question about groups, and groups don't exist until GROUP BY has run. That's what HAVING is for:

SQL
SELECT category, COUNT(*) AS products
FROM products
GROUP BY category
HAVING COUNT(*) >= 2;

HAVING works like WHERE, but on the grouped result, so it can test aggregates like COUNT(*).

WHERE can't do this

SQL
SELECT category, COUNT(*) AS products
FROM products
WHERE COUNT(*) >= 2
GROUP BY category;

The database refuses. Aggregates aren't allowed in WHERE, because WHERE looks at one row at a time, before any counting has happened.

More examples

Customers with more than one order:

SQL
SELECT customer_id, COUNT(*) AS orders
FROM orders
GROUP BY customer_id
HAVING COUNT(*) > 1;

Departments where the average salary is above 100,000:

SQL
SELECT department, ROUND(AVG(salary)) AS avg_salary, COUNT(*) AS staff
FROM employees
GROUP BY department
HAVING AVG(salary) > 100000;

WHERE and HAVING together

They often share a query: WHERE decides which rows go into the groups, and HAVING decides which groups come out. Customers who spent more than 200, not counting cancelled orders:

SQL
SELECT c.name, ROUND(SUM(oi.quantity * p.price), 2) AS spent
FROM customers c
JOIN orders o       ON o.customer_id = c.customer_id
JOIN order_items oi ON oi.order_id = o.order_id
JOIN products p     ON p.product_id = oi.product_id
WHERE o.status <> 'cancelled'
GROUP BY c.name
HAVING SUM(oi.quantity * p.price) > 200
ORDER BY spent DESC;

The order SQL runs a query

You write SELECT first, but the database works through the clauses in this order:

StepClauseWhat happens
1FROM, JOINgather the rows
2WHEREdrop rows that fail the condition
3GROUP BYform the groups
4HAVINGdrop groups that fail the condition
5SELECTwork out the output columns
6ORDER BYsort
7LIMITkeep the first rows

That's why WHERE can't see aggregates (step 2 comes before step 3), and why standard SQL won't let WHERE use an alias defined in SELECT. ORDER BY runs after SELECT, so it can.

Finished this lesson?Mark it complete to earn +20 XP and move your progress on.