Filtering Aggregated Fields Using the Having Clause

Filtering Aggregated Fields Using the Having Clause

Oct 8, 2024 by Robert Gravelle

If you have been writing SQL queries for some time, you are probably quite familiar with the WHERE clause. While it has no effect on aggregated fields, there is a way to filter records according to aggregate values, and that is by using the HAVING clause. This blog will cover how it works as well as provide a few examples on using it in SELECT queries.

Aggregation is typically used in conjunction with grouping. In SQL, that’s accomplished using the GROUP BY clause. Aggregation, together with grouping, allows us to glean high level insights into our data. For example, an eCommerce company might want to track sales over a given time period.

In many cases, we may not want to apply the GROUP BY clause on the entire dataset. In those instances, we can employ the GROUP BY command along with the conditional HAVING clause to filter out unwanted results. Similar to the WHERE clause, HAVING specifies one or more filter conditions, but for a group or an aggregation. As such, HAVING is always placed after the WHERE and GROUP BY clauses but before the (optional) ORDER BY clause:

SELECT column_list
FROM table_name
WHERE where_conditions
GROUP BY column_list
HAVING having_conditions
ORDER BY order_expression

To get a better idea on how HAVING works, let’s run a few SELECT queries against the Sakila Sample Database.

Our first query lists our top movie renters, sorted in descending order, so that the person with the most rentals appears at the top. We’ll use the HAVING clause to remove customers with less than three rentals in order to shorten the list somewhat:

SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  COUNT(r.rental_id) AS total_rentals
FROM 
  customer AS c
    LEFT JOIN rental AS r ON c.customer_id = r.customer_id
GROUP BY c.customer_id
HAVING total_rentals >= 3
ORDER BY total_rentals DESC;

Here is the query and the first page of results in Navicat Premium:

top movie renters (89K)

Judging by those rental numbers, we could have narrowed down the list substantially more!

Filtering Rows Using Both WHERE and HAVING

Just as GROUP BY and ORDER BY are applied at different points in the querying process, so too are WHERE and HAVING. Hence, we can include both to filter results both before and after grouping and aggregation. For example, we can add a WHERE clause to restrict results to the first half of a given year:

SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  COUNT(r.rental_id) AS total_rentals
FROM 
  customer AS c
    LEFT JOIN rental AS r ON c.customer_id = r.customer_id
WHERE r.rental_date BETWEEN '2005-01-01' AND '2005-06-30'
GROUP BY c.customer_id
HAVING total_rentals >= 3
ORDER BY total_rentals DESC;

Once again, here is the above query and the first page of results in Navicat Premium:

top movie renters for first half of 2005 (96K)

Just as the WHERE clause supports multiple conditions using the AND and OR keywords, so too does HAVING. For example, we could find customers whose rental numbers fall within a given range by modifying the HAVING clause to something like the following:

HAVING total_rentals >= 3 AND total_rentals <= 10

In today's blog we learned how to filter grouped and aggregated fields using the HAVING clause.

Interested in Navicat Premium? You can try it for 14 days completely free of charge for evaluation purposes!