Bird
Raised Fist0
SQLquery~10 mins

WHERE vs HAVING mental model in SQL - Visual Side-by-Side Comparison

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - WHERE vs HAVING mental model
Start with Table Data
Apply WHERE filter
Group Data (if GROUP BY used)
Apply HAVING filter on groups
Return final result
Data is first filtered row-by-row using WHERE, then grouped, and groups are filtered using HAVING before final output.
Execution Sample
SQL
SELECT department, COUNT(*) AS emp_count
FROM employees
WHERE salary > 3000
GROUP BY department
HAVING COUNT(*) > 2;
This query filters employees with salary > 3000, groups them by department, then shows only departments with more than 2 such employees.
Execution Table
StepActionData StateFilter AppliedResulting Rows/Groups
1Start with all employeesAll rows from employees tableNoneAll employee rows
2Apply WHERE salary > 3000Rows with salary > 3000Row-level filterFiltered employee rows
3Group by departmentGrouped filtered rowsGroupingGroups of employees per department
4Apply HAVING COUNT(*) > 2Groups with count > 2Group-level filterDepartments with more than 2 employees
5Return final resultFiltered groupsNoneFinal output rows
💡 No more steps; query returns groups filtered by HAVING after WHERE filtering and grouping.
Variable Tracker
VariableStartAfter WHEREAfter GROUP BYAfter HAVINGFinal
RowsAll employeesEmployees with salary > 3000Employees grouped by departmentGroups with count > 2Final filtered groups
CountN/AN/ACount per groupCount > 2 filter appliedCount per returned group
Key Moments - 3 Insights
Why can't we use aggregate functions like COUNT() in WHERE?
WHERE filters rows before grouping, so aggregate functions which need groups are not available yet (see execution_table step 2 vs 4).
Can HAVING be used without GROUP BY?
Yes, HAVING can filter on aggregate results even without GROUP BY, but it filters on the whole result treated as one group (see execution_table step 4).
Does WHERE filter groups or individual rows?
WHERE filters individual rows before grouping, so it affects which rows enter groups (see execution_table step 2).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step is the row-level filter applied?
AStep 3
BStep 2
CStep 4
DStep 5
💡 Hint
Check the 'Filter Applied' column for 'Row-level filter' in execution_table.
According to variable_tracker, what happens to 'Rows' after GROUP BY?
ARows are grouped by department
BRows are counted
CRows are filtered by salary
DRows are returned as final output
💡 Hint
Look at the 'Rows' variable state under 'After GROUP BY' in variable_tracker.
If we remove the WHERE clause, how does the execution_table change at step 2?
AStep 2 applies HAVING filter
BStep 2 groups rows
CStep 2 applies no filter and keeps all rows
DStep 2 returns final result
💡 Hint
Refer to execution_table step 2 description about WHERE filtering.
Concept Snapshot
WHERE filters rows before grouping.
HAVING filters groups after grouping.
WHERE cannot use aggregates like COUNT().
HAVING can filter on aggregates.
Use WHERE for row-level conditions.
Use HAVING for group-level conditions.
Full Transcript
This visual execution shows how SQL processes WHERE and HAVING clauses. First, the database starts with all rows. Then WHERE filters rows individually before any grouping. Next, rows are grouped by the specified column(s). After grouping, HAVING filters groups based on aggregate conditions like COUNT(). Finally, the filtered groups are returned as the query result. WHERE works on raw rows, so it cannot use aggregate functions. HAVING works on groups, so it can use aggregates. This helps understand when to use WHERE versus HAVING in SQL queries.

Practice

(1/5)
1. Which clause should you use to filter rows before grouping in a SQL query?
easy
A. HAVING
B. WHERE
C. GROUP BY
D. ORDER BY

Solution

  1. Step 1: Understand filtering before grouping

    The WHERE clause filters individual rows before any grouping happens in the query.
  2. Step 2: Compare WHERE and HAVING roles

    HAVING filters groups after grouping, so it cannot filter rows before grouping.
  3. Final Answer:

    WHERE -> Option B
  4. Quick Check:

    Filter rows before grouping = WHERE [OK]
Hint: Use WHERE for rows, HAVING for groups after grouping [OK]
Common Mistakes:
  • Using HAVING to filter rows before grouping
  • Confusing GROUP BY as a filter
  • Using ORDER BY to filter data
2. Which of the following SQL queries correctly filters groups having a total sales greater than 1000?
easy
A. SELECT store, SUM(sales) FROM sales_data WHERE SUM(sales) > 1000 GROUP BY store;
B. SELECT store, SUM(sales) FROM sales_data WHERE sales > 1000 GROUP BY store;
C. SELECT store, SUM(sales) FROM sales_data GROUP BY store HAVING SUM(sales) > 1000;
D. SELECT store, SUM(sales) FROM sales_data HAVING SUM(sales) > 1000 GROUP BY store;

Solution

  1. Step 1: Identify correct HAVING usage

    HAVING is used to filter groups based on aggregate functions like SUM.
  2. Step 2: Check query syntax and order

    SELECT store, SUM(sales) FROM sales_data GROUP BY store HAVING SUM(sales) > 1000; correctly uses GROUP BY first, then HAVING with SUM(sales) > 1000.
  3. Final Answer:

    SELECT store, SUM(sales) FROM sales_data GROUP BY store HAVING SUM(sales) > 1000; -> Option C
  4. Quick Check:

    Filter groups by aggregate = HAVING [OK]
Hint: HAVING filters aggregates after GROUP BY [OK]
Common Mistakes:
  • Using WHERE with aggregate functions
  • Placing HAVING before GROUP BY
  • Filtering rows instead of groups
3. Given the table orders(order_id, customer_id, amount), what will this query return?
SELECT customer_id, COUNT(*) AS order_count FROM orders WHERE amount > 50 GROUP BY customer_id HAVING order_count > 2;
medium
A. Customers with total amount over 50
B. All customers with orders over 50 regardless of count
C. Syntax error because alias can't be used in HAVING
D. Customers with more than 2 orders where each order amount is over 50

Solution

  1. Step 1: Understand alias usage in HAVING

    Many SQL databases allow using column aliases like order_count directly in HAVING clause, but standard SQL does not. However, most practical systems support it.
  2. Step 2: Identify correct HAVING syntax

    Using alias in HAVING is often allowed; thus, the query returns customers with more than 2 orders where each order amount is over 50.
  3. Final Answer:

    Customers with more than 2 orders where each order amount is over 50 -> Option D
  4. Quick Check:

    HAVING filters groups; alias usage depends on SQL dialect [OK]
Hint: Use full aggregate in HAVING or alias depending on SQL dialect [OK]
Common Mistakes:
  • Using alias in HAVING clause (may be allowed in some SQL dialects)
  • Confusing WHERE and HAVING filters
  • Assuming HAVING filters rows
4. Identify the error in this SQL query:
SELECT department, AVG(salary) FROM employees HAVING AVG(salary) > 50000 WHERE department LIKE 'Sales%' GROUP BY department;
medium
A. WHERE clause used after HAVING
B. HAVING clause used before GROUP BY
C. Missing alias for AVG(salary)
D. GROUP BY clause missing

Solution

  1. Step 1: Check SQL clause order

    The correct order is WHERE, then GROUP BY, then HAVING.
  2. Step 2: Identify misplaced WHERE clause

    In the query, WHERE appears after HAVING, which is invalid syntax.
  3. Final Answer:

    WHERE clause used after HAVING -> Option A
  4. Quick Check:

    WHERE before GROUP BY, HAVING after [OK]
Hint: WHERE before GROUP BY, HAVING after GROUP BY [OK]
Common Mistakes:
  • Placing WHERE after HAVING
  • Forgetting GROUP BY clause
  • Using HAVING without GROUP BY
5. You want to find all customers who placed more than 3 orders with each order amount greater than 100. Which query correctly applies WHERE and HAVING?
hard
A. SELECT customer_id FROM orders WHERE amount > 100 GROUP BY customer_id HAVING COUNT(*) > 3;
B. SELECT customer_id FROM orders GROUP BY customer_id HAVING COUNT(*) > 3 AND amount > 100;
C. SELECT customer_id FROM orders HAVING COUNT(*) > 3 WHERE amount > 100 GROUP BY customer_id;
D. SELECT customer_id FROM orders WHERE COUNT(*) > 3 GROUP BY customer_id HAVING amount > 100;

Solution

  1. Step 1: Filter rows with WHERE

    Use WHERE to keep only orders with amount > 100 before grouping.
  2. Step 2: Filter groups with HAVING

    Use HAVING to keep customers with more than 3 such orders (COUNT(*) > 3).
  3. Final Answer:

    SELECT customer_id FROM orders WHERE amount > 100 GROUP BY customer_id HAVING COUNT(*) > 3; -> Option A
  4. Quick Check:

    WHERE filters rows, HAVING filters groups [OK]
Hint: WHERE filters rows, HAVING filters groups after grouping [OK]
Common Mistakes:
  • Using HAVING to filter rows
  • Placing WHERE after HAVING
  • Using aggregate in WHERE clause