SQL Execution Funnel

Understanding SQL Execution Order

You write SQL in one order, but the database engine processes it in a completely different sequence! Understanding this underlying execution logic—especially the difference between WHERE and HAVING—is the foundational key to mastering data filtering and avoiding common errors.

Written Order (Syntax)

1. SELECT column_names
2. FROM table_name
3. WHERE condition
4. GROUP BY column_names
5. HAVING group_condition

This is how we type the query. It is designed to read like a natural English sentence, making it easy for humans to formulate.

Execution Order (Logic)

1. FROM (Get the data)
2. WHERE (Filter rows)
3. GROUP BY (Organize into groups)
4. HAVING (Filter groups)
5. SELECT (Pick columns to show)

This is how the database engine actually processes the data step-by-step to optimize performance and apply logic correctly.

Interactive Filter Funnel

Click through the steps below to see exactly how data flows and transforms through each clause of the query.

SELECT Dept, AVG(Salary)
FROM Employees
WHERE Salary > 3500
GROUP BY Dept
HAVING COUNT(*) > 1;

Current Data State

Key Differences: WHERE vs HAVING

WHERE

  • Filters individual rows before any grouping occurs.
  • Cannot use aggregate functions (e.g., SUM(), COUNT(), AVG()).
  • Example: WHERE Salary > 3500 (Checks each person's salary).

HAVING

  • Filters groups after GROUP BY is applied.
  • Primarily used with aggregate functions to evaluate group totals/averages.
  • Example: HAVING COUNT(*) > 1 (Checks the size of the group).

Programming Integration

See how to execute this exact SQL query within application code using SQLite.

import sqlite3

# 1. Connect to the SQLite database
conn = sqlite3.connect('company.db')
cursor = conn.cursor()

# 2. Define the SQL query (The database engine handles the execution order automatically)
query = """
    SELECT Dept, AVG(Salary)
    FROM Employees
    WHERE Salary > 3500
    GROUP BY Dept
    HAVING COUNT(*) > 1;
"""

# 3. Execute the query
cursor.execute(query)

# 4. Fetch and display the results
results = cursor.fetchall()
for row in results:
    print(f"Department: {row[0]}, Average Salary: {row[1]}")

# 5. Close the connection
conn.close()

Knowledge Check

1. Which clause is executed FIRST by the database engine?

2. I want to filter out departments that have an average salary below 4000. Which clause should I use?