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)