Correlated Subquery in SQL Server
What is a correlated subquery?
A correlated subquery is an inner query that refers to a column from the outer query.
It is connected to the current row being processed by the outer query. Conceptually, the subquery is evaluated for each row of the outer query.
Example tables
Employees
| EmployeeId | EmployeeName | DepartmentId | Salary |
|---|---|---|---|
| 1 | Arun | 10 | 60,000 |
| 2 | Banu | 10 | 40,000 |
| 3 | Charles | 20 | 70,000 |
| 4 | Divya | 20 | 50,000 |
Example: Employees earning above their department average
SELECT
E.EmployeeName,
E.DepartmentId,
E.Salary
FROM Employees E
WHERE E.Salary >
(
SELECT AVG(E2.Salary)
FROM Employees E2
WHERE E2.DepartmentId = E.DepartmentId
);
How it works
For each employee:
-
The outer query selects an employee as
E. -
The subquery calculates the average salary for that employee’s department.
-
The employee’s salary is compared with the department average.
-
The employee is returned when the salary is higher.
The correlation is:
E2.DepartmentId = E.DepartmentId
-
E2.DepartmentIdbelongs to the subquery. -
E.DepartmentIdbelongs to the outer query.
Result
| EmployeeName | DepartmentId | Salary |
|---|---|---|
| Arun | 10 | 60,000 |
| Charles | 20 | 70,000 |
Department averages:
-
Department 10:
(60,000 + 40,000) / 2 = 50,000 -
Department 20:
(70,000 + 50,000) / 2 = 60,000
Normal vs correlated subquery
Normal subquery
The inner query runs independently:
SELECT EmployeeName, Salary
FROM Employees
WHERE Salary >
(
SELECT AVG(Salary)
FROM Employees
);
It compares each employee against the overall company average.
Correlated subquery
The inner query depends on the outer row:
SELECT EmployeeName, Salary
FROM Employees E
WHERE Salary >
(
SELECT AVG(E2.Salary)
FROM Employees E2
WHERE E2.DepartmentId = E.DepartmentId
);
It compares each employee against their own department average.
| Normal subquery | Correlated subquery |
|---|---|
| Runs independently | Depends on the outer query |
| Does not reference outer columns | References at least one outer column |
| Usually calculates one general result | Calculates or checks a result for each outer row |
| Often simpler | Useful for row-specific comparisons |
Correlated subquery with EXISTS
Find customers who have at least one order:
SELECT
C.CustomerId,
C.CustomerName
FROM Customers C
WHERE EXISTS
(
SELECT 1
FROM Orders O
WHERE O.CustomerId = C.CustomerId
);
The correlation is:
O.CustomerId = C.CustomerId
EXISTS returns true as soon as SQL Server finds a matching order.
Correlated subquery with NOT EXISTS
Find customers who have never placed an order:
SELECT
C.CustomerId,
C.CustomerName
FROM Customers C
WHERE NOT EXISTS
(
SELECT 1
FROM Orders O
WHERE O.CustomerId = C.CustomerId
);
Usage
Correlated subqueries are commonly used for:
-
Comparing a row with its group average
-
Checking whether related records exist
-
Finding rows without related records
-
Finding maximum or minimum values within each group
-
Applying row-specific filtering conditions
Key points
-
It references a column from the outer query.
-
It cannot normally run independently because it needs the outer row.
-
Table aliases are important for distinguishing inner and outer references.
-
It is commonly used with
EXISTSandNOT EXISTS. -
Conceptually, it runs once for every outer row.
-
SQL Server may optimize it internally into a join or another efficient operation.
-
Performance can become slow on large tables if the correlation columns are not indexed.
-
Always check the execution plan for performance-sensitive queries.
Interview answer:
“A correlated subquery is a subquery that references columns from its outer query. It produces or checks a result based on the current outer row and is commonly used for group-based comparisons and EXISTS or NOT EXISTS checks.”