SQL HAVING Clause


When working with SQL, one of the most common tasks is grouping data. Whether you’re calculating sums, averages, or counts, grouping is essential for analyzing large datasets. However, after grouping data, you may want to filter the results based on aggregate values. That’s where the HAVING clause comes in.


1. What is the SQL HAVING Clause?

The HAVING clause is used to filter records after the GROUP BY operation has been applied. It is typically used with aggregate functions like COUNT(), SUM(), AVG(), MAX(), and MIN() to filter groups of data based on the results of these functions.

In simple terms, HAVING allows you to filter grouped data, whereas the WHERE clause filters data before it is grouped.


2. Syntax of the SQL HAVING Clause

The general syntax for using the HAVING clause is as follows:

SELECT column1, column2, aggregate_function(column3)
FROM table_name
WHERE condition
GROUP BY column1, column2
HAVING aggregate_condition;
  • SELECT: Specifies the columns or aggregate functions to retrieve.
  • FROM: Specifies the table to query.
  • WHERE: Filters data before grouping (optional).
  • GROUP BY: Groups data based on specified columns.
  • HAVING: Filters groups after aggregation (optional).

3. Difference Between WHERE and HAVING

While both WHERE and HAVING clauses filter data, they work at different stages of query execution:

  • WHERE filters rows before aggregation, meaning it works on individual rows.
  • HAVING filters groups of rows after aggregation, meaning it works on the results of aggregate functions.

Key Difference:

  • WHERE cannot be used with aggregate functions.
  • HAVING is used to filter based on aggregate conditions after grouping.

Example Comparison:

-- WHERE Clause (Filters rows before grouping)
SELECT department, AVG(salary)
FROM employees
WHERE salary > 50000
GROUP BY department;

-- HAVING Clause (Filters after aggregation)
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
  • The first query uses WHERE to filter individual employees with a salary above $50,000 before the aggregation.
  • The second query uses HAVING to filter departments where the average salary exceeds $50,000 after grouping.

4. Basic Example of Using HAVING

Let’s use the HAVING clause in a simple example. Suppose you have an orders table with columns order_id, customer_id, and order_amount. You want to find customers who have placed more than 3 orders, with each order amount exceeding $100.

SELECT customer_id, COUNT(order_id) AS total_orders, SUM(order_amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING COUNT(order_id) > 3 AND SUM(order_amount) > 300;

Explanation:

  • The GROUP BY clause groups the data by customer_id.
  • The COUNT(order_id) counts the total number of orders for each customer.
  • The SUM(order_amount) calculates the total spent by each customer.
  • The HAVING clause ensures that only customers who have placed more than 3 orders and spent over $300 are included in the result.

5. Using HAVING with Multiple Aggregate Functions

You can use the HAVING clause with multiple aggregate functions to apply more complex filters to grouped data.

Example: Using Multiple Aggregates

SELECT employee_id, COUNT(order_id) AS total_orders, SUM(order_amount) AS total_sales
FROM orders
GROUP BY employee_id
HAVING COUNT(order_id) > 5 AND SUM(order_amount) > 1000;

Explanation:

  • The query counts the number of orders (COUNT(order_id)) and sums the order_amount (SUM(order_amount)) for each employee.
  • The HAVING clause filters employees who have made more than 5 orders and have generated sales greater than $1000.

6. Combining WHERE and HAVING

You can combine the WHERE and HAVING clauses in the same query to filter data at both stages of the query execution.

Example: Using WHERE and HAVING Together

SELECT department_id, AVG(salary) AS average_salary
FROM employees
WHERE hire_date > '2020-01-01'
GROUP BY department_id
HAVING AVG(salary) > 50000;

Explanation:

  • The WHERE clause filters employees hired after January 1, 2020.
  • The GROUP BY groups the employees by department_id.
  • The HAVING clause filters groups (departments) where the average salary exceeds $50,000.

7. Using HAVING with Complex Conditions

The HAVING clause allows you to apply complex conditions involving aggregate functions. You can also combine logical operators like AND, OR, and NOT for more advanced filtering.

Example: Complex Condition with HAVING

SELECT department_id, COUNT(employee_id) AS num_employees, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING COUNT(employee_id) > 10 AND AVG(salary) < 60000;

Explanation:

  • The query groups employees by department and calculates the number of employees (COUNT(employee_id)) and the average salary (AVG(salary)).
  • The HAVING clause filters departments with more than 10 employees and an average salary under $60,000.

8. Common Mistakes to Avoid with HAVING

  • Using HAVING without GROUP BY: The HAVING clause requires a GROUP BY clause unless you're using aggregate functions.
  • Confusing WHERE with HAVING: Always remember that WHERE filters rows before grouping, while HAVING filters groups after aggregation.
  • Using HAVING on non-aggregated columns: HAVING should be used to filter based on aggregated values (like COUNT(), SUM(), etc.). For non-aggregated columns, use WHERE instead.