SQL HAVING Clause for Beginners

In SQL, the HAVING clause can be used to specify a search condition for a group or an aggregate.

The HAVING clause is typically used with the GROUP BY clause. In cases where it’s not, there is an implicit single, aggregated group.

The HAVING clause is similar to the WHERE clause, except that WHERE filters individual rows, whereas HAVING filters groups. The WHERE clause filters data before it is grouped, whereas HAVING filters data after it is grouped.

Example 1 – HAVING with COUNT()

Suppose we have the following table:

SELECT * FROM Pets;

Result:

+---------+-------------+-----------+-----------+------------+ | PetId   | PetTypeId   | OwnerId   | PetName   | DOB        | |---------+-------------+-----------+-----------+------------| | 1       | 2           | 3         | Fluffy    | 2020-11-20 | | 2       | 3           | 3         | Fetch     | 2019-08-16 | | 3       | 2           | 2         | Scratch   | 2018-10-01 | | 4       | 3           | 3         | Wag       | 2020-03-15 | | 5       | 1           | 1         | Tweet     | 2020-11-28 | | 6       | 3           | 4         | Fluffy    | 2020-09-17 | | 7       | 3           | 2         | Bark      | NULL       | | 8       | 2           | 4         | Meow      | NULL       | +---------+-------------+-----------+-----------+------------+

We could run the following query against this table:

SELECT PetTypeId, COUNT(PetTypeId) AS Count FROM Pets GROUP BY PetTypeId HAVING COUNT(PetTypeId) > 2 ORDER BY Count DESC;

Result:

+-------------+---------+ | PetTypeId   | Count   | |-------------+---------| | 3           | 4       | | 2           | 3       | +-------------+---------+

In this case, we used the HAVING clause in conjunction with the GROUP BY clause to return just those rows that have a COUNT(PetTypeId) of greater than 2. This uses the COUNT() function, which is a SQL standard aggregate function available in most major RDBMSs.

If we omit the HAVING clause, we get one more result:

SELECT PetTypeId, COUNT(PetTypeId) AS Count FROM Pets GROUP BY PetTypeId ORDER BY Count DESC;

Result:

+-------------+---------+ | PetTypeId   | Count   | |-------------+---------| | 3           | 4       | | 2           | 3       | | 1           | 1       | +-------------+---------+

Example 2 – HAVING with SUM()

Here’s another example. This time we use the HAVING clause with the SUM() function, which is another aggregate function available in most major RDBMSs (see SQLite SUM() for another example).

SELECT CountryCode, District, SUM(Population) AS Population FROM City WHERE CountryCode IN ('AGO', 'ARE', 'AUS') GROUP BY CountryCode, District HAVING SUM(Population) > 1000000 ORDER BY CountryCode;

Result:

+---------------+-----------------+--------------+ | CountryCode   | District        | Population   | |---------------+-----------------+--------------| | AGO           | Luanda          | 2022000      | | AUS           | New South Wales | 3993949      | | AUS           | Queensland      | 1805236      | | AUS           | Victoria        | 2990711      | | AUS           | West Australia  | 1096829      | +---------------+-----------------+--------------+

Example 3 – HAVING with the IN Operator

You’re not limited to just the =, <, >=, IN, LIKE, etc).

Here’s an example that uses the IN operator to specify a range of aggregate values to return.

SELECT CountryCode, District, SUM(Population) AS Population FROM City WHERE CountryCode IN ('AGO', 'ARE', 'AUS') GROUP BY CountryCode, District HAVING SUM(Population) IN (2022000, 3993949, 2990711) ORDER BY CountryCode;

Result:

+---------------+-----------------+--------------+ | CountryCode   | District        | Population   | |---------------+-----------------+--------------| | AGO           | Luanda          | 2022000      | | AUS           | New South Wales | 3993949      | | AUS           | Victoria        | 2990711      | +---------------+-----------------+--------------+

Example 4 – HAVING without a GROUP BY Clause

Although HAVING is usually used with the GROUP BY clause, it can also be used without it. When used without it, there is an implicit single, aggregated group.

The results you get may depend on your DBMS, but here’s an example that was done in SQL Server.

SELECT SUM(Population) AS Population FROM City HAVING SUM(Population) > 2000000;

Result:

+--------------+ | Population   | |--------------| | 1429559884   | +--------------+

This example simply returns the aggregate population of all cities in the table.

Here’s what happens if we swap the greater than operator (>) with a less than operator (<).

SELECT SUM(Population) AS Population FROM City HAVING SUM(Population) < 2000000;

Result:

(0 rows affected)