Correlated subquery execution model in SQL - Time & Space Complexity
Start learning this pattern below
Jump into concepts and practice - no test required
When using correlated subqueries, the database runs a smaller query for each row of the main query.
We want to understand how this repeated work grows as the data gets bigger.
Analyze the time complexity of the following SQL query with a correlated subquery.
SELECT e.employee_id, e.name
FROM employees e
WHERE e.salary > (
SELECT AVG(salary)
FROM employees
WHERE department_id = e.department_id
);
This query finds employees whose salary is above the average salary in their own department.
Look for repeated work inside the query.
- Primary operation: The subquery runs once for each employee row.
- How many times: As many times as there are employees (n times).
Each employee triggers a subquery that scans employees in their department.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 times scanning small groups |
| 100 | About 100 times scanning groups of employees |
| 1000 | About 1000 times scanning groups, more work overall |
Pattern observation: The total work grows roughly with the square of the number of employees if departments are evenly sized.
Time Complexity: O(n * m)
This means the query work grows with the number of employees times the average size of their departments.
[X] Wrong: "The subquery runs just once, so the query is fast regardless of data size."
[OK] Correct: The subquery depends on each employee's department, so it runs repeatedly, increasing total work as data grows.
Understanding how correlated subqueries work helps you explain query performance clearly and shows you can think about how databases handle repeated work.
"What if the subquery was uncorrelated and ran only once? How would the time complexity change?"
Practice
Solution
Step 1: Understand subquery types
A correlated subquery depends on the outer query's current row to run.Step 2: Identify correlation
It uses columns from the outer query inside the subquery's WHERE clause.Final Answer:
A subquery that uses values from the outer query to filter results -> Option BQuick Check:
Correlated subquery = uses outer query values [OK]
- Thinking subquery runs once independently
- Confusing with JOIN operations
- Assuming it returns only aggregates
Solution
Step 1: Identify correlation in subquery
SELECT e.name FROM employees e WHERE e.salary > (SELECT AVG(salary) FROM employees WHERE department = e.department) uses 'e.department' inside the subquery, linking it to the outer query.Step 2: Check other options
SELECT e.name FROM employees e WHERE e.salary > (SELECT AVG(salary) FROM employees) has no reference to outer query in subquery; the option with 'salary > 50000' lacks a subquery and the JOIN option is not a subquery.Final Answer:
SELECT e.name FROM employees e WHERE e.salary > (SELECT AVG(salary) FROM employees WHERE department = e.department) -> Option AQuick Check:
Correlation needs outer query column inside subquery [OK]
- Missing outer query reference inside subquery
- Confusing JOIN with subquery
- Using subquery without correlation
employees(id, name, department, salary) and the query:SELECT e1.name FROM employees e1 WHERE e1.salary > (SELECT AVG(e2.salary) FROM employees e2 WHERE e2.department = e1.department);
What does this query return?
Solution
Step 1: Understand the subquery correlation
The subquery calculates average salary for the department of the current employee (e1.department).Step 2: Compare salaries
The outer query selects employees whose salary is greater than that department average.Final Answer:
Employees whose salary is above the average salary of their own department -> Option AQuick Check:
Salary > department average = Employees whose salary is above the average salary of their own department [OK]
- Assuming average is for all employees
- Ignoring the correlation condition
- Confusing with simple WHERE salary > value
SELECT c.customer_id FROM customers c WHERE c.orders_count > (SELECT AVG(o.orders_count) FROM orders o WHERE o.customer_id = c.customer_id);
Solution
Step 1: Analyze correlation
The subquery correctly uses 'c.customer_id' from the outer query in its WHERE clause.Step 2: Check aggregation and output
AVG(o.orders_count) is an aggregate that returns a single scalar value, even for customers with multiple orders.Final Answer:
The subquery references the outer query correctly; no error -> Option DQuick Check:
Subquery must return single value for comparison [OK]
- Thinking AVG returns multiple rows without GROUP BY
- Assuming alias 'o' is undefined
- Believing SUM is needed instead of AVG
Solution
Step 1: Identify correlation condition
SELECT p.product_name FROM products p WHERE p.price > (SELECT AVG(price) FROM products WHERE category = p.category) uses 'p.category' inside the subquery to calculate average price per category, correlating outer and inner queries.Step 2: Verify other options
SELECT p.product_name FROM products p WHERE p.price > (SELECT AVG(price) FROM products) compares to overall average, not per category; the option using JOIN with categories uses a JOIN but no subquery; the option using > ALL compares to all individual prices, not average.Final Answer:
SELECT p.product_name FROM products p WHERE p.price > (SELECT AVG(price) FROM products WHERE category = p.category) -> Option CQuick Check:
Correlated subquery filters by category [OK]
- Using overall average instead of per category
- Confusing JOIN with subquery
- Using ALL instead of AVG in subquery
