Title tag: Describe and Write Subqueries in SQL Server 2025 Meta description: What subqueries are, when to use them, the different kinds, and a worked example, written for Transact-SQL in SQL Server 2025.
| Lesson 10 | Using subqueries |
| Objective | Describe and Write Subqueries in SQL |
WHERE or HAVING clause of an outer statement, or inside another subquery. Up to 32 levels of nesting are possible in SQL Server 2025, though the practical limit depends on available memory and how complex the rest of the query is.
EXISTS. In that specific case, it is usually preferable to construct a join instead.
SELECT statement enclosed in parentheses, and can appear in a WHERE, FROM, SELECT, or HAVING clause. Subqueries are generally categorized by what they return:
IN keyword follows this general syntax:
SELECT column(s)
FROM table(s)
WHERE column IN (subquery)
IN keyword in a WHERE clause restricts a query's results to values that match a list of values produced by the subquery. You can use a subquery anywhere an expression is allowed within a SELECT, UPDATE, INSERT, or DELETE statement, with one exception: it cannot appear in the ORDER BY clause of any of these statements.
SELECT Salary
FROM Employees
WHERE EmployeeID IN (SELECT EmployeeID
FROM ActiveEmployee)
This retrieves salaries only for employees who also appear in the ActiveEmployee table. Conceptually, SQL Server evaluates the innermost query first, building a result set of EmployeeIDs from ActiveEmployee, and then selects salaries from Employees only where the EmployeeID matches one from that result set. This innermost-first model is how Microsoft's own documentation explains nested subqueries, though it describes the logical result rather than a guarantee of exactly how the query optimizer executes the statement internally; the optimizer is free to choose a different physical execution plan that produces the same result.
IN form above, a few other subquery patterns are worth knowing.
SELECT Name, (SELECT AVG(Salary) FROM Employees) AS AvgSal
FROM Employees;
SELECT * FROM Orders
WHERE CustomerID IN (SELECT CustomerID FROM Customers WHERE City = 'NY');
FROM clause, standing in for a table. A derived table must be given an alias:
SELECT d.Dept, s.Total
FROM Departments d
JOIN (SELECT DeptID, SUM(Amount) AS Total FROM Sales GROUP BY DeptID) s
ON d.DeptID = s.DeptID;
SELECT statement nested inside another statement, usable in a WHERE, FROM, SELECT, or HAVING clause, up to 32 levels deep.EXISTS) being the main case where a join tends to be faster.