The difference between the HAVING and WHERE clauses is that WHERE filters individual rows before grouping takes place, while HAVING filters groups after they have been created with GROUP BY. Understanding this timing explains why aggregate conditions such as SUM(amount) > 1000 belong in HAVING, while ordinary row conditions such as status = 'paid' usually belong in WHERE.
Introduction
SQL queries often need more than one kind of filtering. A sales report might need to exclude cancelled orders, group the remaining orders by customer, and then display only customers whose total spending exceeds a particular amount. These are related but distinct operations:
- Remove unwanted source rows.
- Group the remaining rows.
- Calculate summaries for each group.
- Remove groups whose summaries do not meet the requirement.
The WHERE clause handles the first operation. Day to day, the HAVING clause handles the final operation. Confusing them can produce an error, incorrect totals, or a query that performs unnecessary work.
The Core Difference
A simple rule is:
Use
WHEREto filter rows before aggregation andHAVINGto filter groups after aggregation And it works..
Consider an orders table containing customer_id, status, and amount That's the part that actually makes a difference..
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
HAVING SUM(amount) > 1000;
This query works in three stages:
WHERE status = 'paid'keeps only paid order rows.GROUP BY customer_idcombines those rows by customer.HAVING SUM(amount) > 1000keeps only customer groups whose total exceeds 1,000.
If the HAVING condition were placed in WHERE, the database would need to evaluate a group-level total before the groups existed. That is why a direct aggregate condition is not valid in a standard WHERE clause Surprisingly effective..
How SQL Logically Processes These Clauses
The simplified logical order of a grouped query is:
FROMandJOINWHEREGROUP BY- Aggregate calculations
HAVINGSELECTORDER BY
A database optimizer may physically rearrange operations to improve performance, but it must preserve these logical results.
WHERE: Filtering the Input
WHERE evaluates each row available after the FROM and JOIN operations. It can reference ordinary columns but cannot directly use an aggregate result such as COUNT(*) or SUM(amount).
SELECT department, COUNT(*) AS employee_count
FROM employees