Skip to content
wannacode

HAVING: a condition for the groups

In short: HAVING filters groups after GROUP BY with a condition on an aggregate such as SUM(total) > 100, which WHERE cannot do because it runs before grouping.

Problem

The loyalty card

The shop launches a loyalty card: customers with more than 3 orders get one. You know how to count the orders of each customer with GROUP BY customer_id. That gives 18 rows. How do you keep only those with more than 3?

WHERE will not do: it looks at single orders, and the count belongs to the whole customer.

The idea

HAVING

HAVING is a condition for the groups. It goes after GROUP BY, and it can contain an aggregate:

SQLdatabase: shop

Four customers. The groups are made, the count is worked out for each, and HAVING keeps only the groups for which the condition is true.

Try it

The big orders

For free delivery we need the orders over 30 €. The field shows the value of each order. Keep only the ones over 30 €.

SQLdatabase: shop

See it

SUM in WHERE

Almost everyone's first attempt uses WHERE. Run it:

SQLdatabase: shop

SQLite stops with “misuse of aggregate”: an aggregate in a place where it does not belong. In WHERE the database looks at the rows one by one. There are no groups yet, so there is nothing to add up.

The idea

WHERE and HAVING together

The two do not get in each other's way. They work in different places:

  • WHERE filters the rows before the groups;
  • HAVING filters the groups after them.

The loyalty card without the cancelled orders:

SQLdatabase: shop

Customer 7 dropped out. They have 4 orders, but one is cancelled. WHERE removed it before the groups were made, and 3 were left in their group.

Put a condition that looks at a single row (status, a date, a price) in WHERE. It cuts down the rows the database has to group. Leave only the conditions on aggregates in HAVING.

Try it

Only once

Marketing wants to write to the customers who ordered exactly once in 2026. Count all orders, cancelled ones too. Show customer_id and the number of their orders from 2026.

SQLdatabase: shop

Exercise

Two reports

1. Suppliers give a discount on the products we sell a lot of. Which products have sold at least 15 items?

Show product_id and the items sold for the products with at least 15 items sold.

SQLdatabase: shop

2. In which months were there at least 6 orders? Those months need more people in the warehouse.

Show the month (year-month) and the number of orders for the months with at least 6 orders.

SQLdatabase: shop

Test

Check yourself

1. Which condition finds the orders over 30 €?
2. When is WHERE applied?
3. Customer 7 has 4 orders, one of them cancelled. Do they come out with WHERE status <> 'cancelled' … HAVING COUNT(*) > 3?
4. What does the error “misuse of aggregate function SUM()” mean?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·