Types of Sub-Queries
A sub-query is a query inside another query, in parentheses. An uncorrelated one runs once on its own; a correlated one uses the outer query's row and runs once per row.
Journeyman · T-SQL · SQL · Updated
After this lesson you can
- Write a sub-query in parentheses, and tell an uncorrelated sub-query from a correlated one
Key takeaways
- A sub-query is a query inside another query, in parentheses, and the outer query uses its answer.
- An uncorrelated sub-query doesn't depend on the outer query: SQL Server runs it once, and you can run it on its own to test it.
- A correlated sub-query uses a value from the outer query's row, such as
p.CategoryId, so it runs once per row and can't run on its own. - Use a correlated sub-query when each row needs its own answer, such as its own category's average; use a join when a join will do.
A sub-query is a query written inside another query, in parentheses. The inner query answers a question, and the outer query uses the answer.
Uncorrelated: runs once, on its own
Say you want the Dairy Products, but you don't know that category's id. One query finds the id:
SELECT CategoryId
FROM Categories
WHERE CategoryName = 'Dairy Products';
Another lists products by id. Put the first inside the second, and you don't need to know the id at all:
SELECT ProductName, UnitPrice
FROM Products
WHERE CategoryId = (
SELECT CategoryId
FROM Categories
WHERE CategoryName = 'Dairy Products'
)
ORDER BY UnitPrice DESC;
| ProductName | UnitPrice |
|---|---|
| Raclette Courdavault | 55.00 |
| Queso Manchego La Pastora | 38.00 |
| Gudbrandsdalsost | 36.00 |
| Mozzarella di Giovanni | 34.80 |
(10 rows in all.) The sub-query is uncorrelated: it doesn't depend on the outer query. You can select it and run it by itself, which makes it easy to test. SQL Server runs it once and uses its answer.
The same question can be written as a join:
SELECT p.ProductName, p.UnitPrice
FROM Products AS p
INNER JOIN Categories AS c
ON p.CategoryId = c.CategoryId
WHERE c.CategoryName = 'Dairy Products';
Correlated: uses the outer row
A correlated sub-query uses a value from the outer query's current row, so it can't run on its own. This one finds each product's category name:
SELECT TOP (4) ProductName
, (
SELECT CategoryName
FROM Categories AS c
WHERE c.CategoryId = p.CategoryId
) AS CategoryName
FROM Products AS p
ORDER BY ProductId;
| ProductName | CategoryName |
|---|---|
| Chai | Beverages |
| Chang | Beverages |
| Aniseed Syrup | Condiments |
| Chef Anton's Cajun Seasoning | Condiments |
The inner query uses p.CategoryId, from the outer query's row, so it runs once per row. On a big table that can be slow; here, a join does the same job, and usually better.
Correlated, when a join won't do
Some questions need the correlation. Which products cost more than twice their own category's average? Each product's comparison needs a different average:
SELECT p.ProductName, p.UnitPrice, p.CategoryId
FROM Products AS p
WHERE p.UnitPrice > (
SELECT AVG(p2.UnitPrice) * 2
FROM Products AS p2
WHERE p2.CategoryId = p.CategoryId
)
ORDER BY p.CategoryId;
| ProductName | UnitPrice | CategoryId |
|---|---|---|
| Côte de Blaye | 263.50 | 1 |
| Sir Rodney's Marmalade | 81.00 | 3 |
| Thüringer Rostbratwurst | 123.79 | 6 |
| Carnarvon Tigers | 62.50 | 8 |
Products appears twice, with two aliases: p for the product being checked, p2 for the products averaged.
| Uncorrelated | Correlated | |
|---|---|---|
| Uses the outer query's row | No | Yes |
| Can be run on its own | Yes | No |
| Runs | Once | Once per outer row |
Check yourself
1 question to try on the lesson page.
So what
A sub-query lets one query ask another for an answer. Test uncorrelated ones on their own first; use correlated ones when each row needs its own answer, and a join when a join will do.