đ A Recursive Common Table Expression (Recursive CTE) is a special type of Common Table Expression (CTE) that references itself. It is used to process hierarchical or tree-structured data, such as employee-manager relationships, organizational charts, category trees, file systems, and family trees.
đ What is a Recursive CTE?
A Recursive CTE repeatedly executes itself until a termination condition is met. It consists of two parts:
- Anchor Member â Returns the initial result set.
- Recursive Member â References the CTE itself and continues retrieving additional rows.
Information
đ¯ Why Use Recursive CTEs?
Recursive CTEs simplify queries involving hierarchical relationships without requiring repeated self-joins or procedural loops.
- đ Build organizational hierarchies.
- đ Traverse parent-child relationships.
- đ Display folder or category structures.
- đ Generate sequences and numbers.
- đ Explore graph-like data structures.
đ Basic Syntax
Recursive CTE Syntax
WITH RECURSIVE cte_name AS
(
-- Anchor Member
SELECT ...
UNION ALL
-- Recursive Member
SELECT ...
FROM table_name
JOIN cte_name
ON ...
)
SELECT *
FROM cte_name;Important
đ Sample Table
Consider the following Employees table:
| EmployeeID | EmployeeName | ManagerID | Department |
|---|---|---|---|
| 1 | John | NULL | Management |
| 2 | Alice | 1 | IT |
| 3 | Bob | 1 | Finance |
| 4 | David | 2 | IT |
| 5 | Emma | 2 | IT |
| 6 | Frank | 4 | IT |
đĄ Basic Recursive CTE Example
Display the complete employee hierarchy starting from the top-level manager.
Employee Hierarchy
WITH RECURSIVE EmployeeHierarchy AS
(
-- Anchor Member
SELECT EmployeeID,
EmployeeName,
ManagerID,
1 AS Level
FROM Employees
WHERE ManagerID IS NULL
UNION ALL
-- Recursive Member
SELECT e.EmployeeID,
e.EmployeeName,
e.ManagerID,
h.Level + 1
FROM Employees e
JOIN EmployeeHierarchy h
ON e.ManagerID = h.EmployeeID
)
SELECT *
FROM EmployeeHierarchy
ORDER BY Level,
EmployeeID;Result:
| EmployeeName | ManagerID | Level |
|---|---|---|
| John | NULL | 1 |
| Alice | 1 | 2 |
| Bob | 1 | 2 |
| David | 2 | 3 |
| Emma | 2 | 3 |
| Frank | 4 | 4 |
đ Understanding the Execution
- The anchor member selects the root employee ( John).
- The recursive member finds employees managed by John.
- The recursion continues by finding employees managed by Alice, Bob, and others.
- The process ends when no additional employees are found.
đ Generating a Sequence of Numbers
Recursive CTEs can generate simple sequences without requiring a numbers table.
Generate Numbers from 1 to 10
WITH RECURSIVE Numbers AS
(
SELECT 1 AS Number
UNION ALL
SELECT Number + 1
FROM Numbers
WHERE Number < 10
)
SELECT *
FROM Numbers;đŗ Recursive CTE for Categories
Recursive CTEs are useful for displaying category hierarchies.
Category Hierarchy
WITH RECURSIVE CategoryTree AS
(
SELECT CategoryID,
CategoryName,
ParentCategoryID
FROM Categories
WHERE ParentCategoryID IS NULL
UNION ALL
SELECT c.CategoryID,
c.CategoryName,
c.ParentCategoryID
FROM Categories c
JOIN CategoryTree ct
ON c.ParentCategoryID = ct.CategoryID
)
SELECT *
FROM CategoryTree;đ Common Uses of Recursive CTEs
| Use Case | Description |
|---|---|
| Employee Hierarchies | Display managers and subordinates. |
| Category Trees | Navigate parent-child categories. |
| Folder Structures | Display nested directories. |
| Family Trees | Represent ancestor-descendant relationships. |
| Number Generation | Create sequences for calculations and reports. |
âī¸ Recursive CTE vs Standard CTE
| Feature | Standard CTE | Recursive CTE |
|---|---|---|
| Self-Reference | â No | â Yes |
| Hierarchy Support | â No | â Yes |
| Sequence Generation | â No | â Yes |
| Typical Use | Organize complex queries. | Traverse recursive relationships. |
đŧ Real-World Example
A company wants to display its complete organizational structure, showing each employee's reporting level from the CEO down to junior staff.
Organization Hierarchy Report
WITH RECURSIVE EmployeeHierarchy AS
(
SELECT EmployeeID,
EmployeeName,
ManagerID,
1 AS Level
FROM Employees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.EmployeeID,
e.EmployeeName,
e.ManagerID,
h.Level + 1
FROM Employees e
JOIN EmployeeHierarchy h
ON e.ManagerID = h.EmployeeID
)
SELECT EmployeeName,
Level
FROM EmployeeHierarchy
ORDER BY Level,
EmployeeName;This query produces a clear hierarchy showing every employee's position within the organization.
â ī¸ Common Mistakes
- â Forgetting to include an anchor member.
- â Omitting a termination condition, causing infinite recursion.
- â Using UNION instead of UNION ALL, which can unnecessarily remove duplicate rows and reduce performance.
- â Creating circular parent-child relationships that cause recursion loops.
Warning
â ī¸ Best Practices
Best Practice
đ Key Points to Remember
- đ A Recursive CTE references itself.
- đ It consists of an anchor member and a recursive member.
- đ It is ideal for hierarchical and tree-structured data.
- đ UNION ALL is commonly used to combine the anchor and recursive members.
- đ The recursion stops when no additional rows are returned or when the recursion limit is reached.
- đ Recursive CTEs can also generate number sequences and traverse graphs.