SQL WHERE vs HAVING
SQL WHERE vs HAVING: When to Use Each
WHERE and HAVING both filter rows, which is exactly why they're so easy to mix up. The difference comes down to one thing: when in the query's execution each one runs.
๐ The Core Rule
WHERE filters rows before grouping happens. HAVING filters groups after GROUP BY has already collapsed the rows. This is why HAVING can filter on aggregate functions (like COUNT or SUM) and WHERE cannot.
๐งช Why WHERE Can't Filter on Aggregates
-- ❌ This throws an error in most databases
SELECT department, COUNT(*) AS employee_count
FROM employees
WHERE COUNT(*) > 5
GROUP BY department;
This fails because WHERE runs before COUNT(*) has even been calculated — at the point WHERE executes, there's no "count" yet to filter on.
๐งช The Correct Version, Using HAVING
SELECT department, COUNT(*) AS employee_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
This works because HAVING runs after grouping and aggregation are complete — COUNT(*) has already been calculated per group, so HAVING can filter on it.
๐ฏ Using Both Together
WHERE and HAVING are often combined — WHERE narrows down the raw rows first (cheaper, filters early), then HAVING filters the resulting groups:
SELECT department, COUNT(*) AS employee_count
FROM employees
WHERE hire_date >= '2024-01-01'
GROUP BY department
HAVING COUNT(*) > 5;
Here, WHERE first keeps only employees hired since 2024, then grouping happens, then HAVING keeps only departments with more than 5 such employees.
๐ Execution Order (Why This Matters)
SQL doesn't execute in the order you write it. The actual logical order is roughly:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
WHERE happens early, working on raw individual rows. HAVING happens late, working on already-grouped results. Understanding this order is what makes the WHERE-vs-HAVING rule make sense instead of feeling arbitrary.
⚠️ Common Mistakes
- Trying to filter on an aggregate function using WHERE — always use HAVING for that instead
- Using HAVING for a filter that could be done with WHERE — this is a performance mistake, since WHERE filters rows earlier (cheaper) while HAVING filters after the expensive GROUP BY has already run
- Forgetting HAVING requires GROUP BY to be meaningful — filtering on an aggregate without grouping produces a single summary row, which is rarely what's intended
๐ Related Posts
- GROUP BY vs PARTITION BY in SQL — What's the Difference?
- SQL JOIN Types Explained (INNER, LEFT, RIGHT, FULL) with Examples
Comments
Post a Comment