Using CTEs (Common Table Expressions) in SQL Server
Posted: (EET/GMT+2)
If you need to break a complex SQL query into smaller steps, a CTE (Common Table Expression) is a simple way to do it. SQL Server has good support for them, you just need to learn the syntax.
A CTE can be thought of as being a temporary result set that you define. To do so, start your query using the
WITH keyword. The result set only exists for the duration of that query.
Let's take a basic example:
WITH ActiveCustomers AS
(
SELECT CustomerId, Name
FROM dbo.Customers
WHERE IsActive = 1
)
SELECT *
FROM ActiveCustomers;
This works like a named subquery. It can make queries easier to read compared to nested SELECT statements.
You can also use multiple CTEs in the same query, just separate them with a comma:
WITH ActiveCustomers AS
(
SELECT CustomerId, Name
FROM dbo.Customers
WHERE IsActive = 1
),
RecentOrders AS
(
SELECT OrderId, CustomerId
FROM dbo.Orders
WHERE CreatedUtc > DATEADD(day, -30, GETUTCDATE())
)
SELECT c.Name, o.OrderId
FROM ActiveCustomers c
JOIN RecentOrders o ON c.CustomerId = o.CustomerId;
Another common use case is recursive queries, for example when working with hierarchical data.
WITH CategoryTree AS
(
SELECT CategoryId, ParentCategoryId, Name
FROM dbo.Categories
WHERE ParentCategoryId IS NULL
UNION ALL
SELECT c.CategoryId, c.ParentCategoryId, c.Name
FROM dbo.Categories c
INNER JOIN CategoryTree t ON c.ParentCategoryId = t.CategoryId
)
SELECT *
FROM CategoryTree;
This example walks a parent-child hierarchy starting from the root.
A few practical notes:
- A CTE only exists for the duration of the statement. It is not stored permanently anywhere.
- CTEs can improve readability, especially for complex queries.
- A CTE does not automatically improve performance compared to subqueries.
- Recursive CTEs are useful for hierarchical data like trees and organizational structures.
The rule of thumb is simple: use CTEs to make complex queries easier to read and structure, especially when you would otherwise use nested subqueries.
Happier querying!