Advanced SQL & Data Engineering • Training 04
Article-Training • SQL Server–Friendly Series

Recursive CTEs

Traverse Hierarchies, Trees and Parent-Child Data Safely

Recursive CTEs let SQL Server walk hierarchical data using an anchor, a recursive step and a stop condition.

Anchor → Parent/Child Match → Next Level → Repeat → Stop
CEO
→
Managers
→
Teams
Root
→
Children
→
Leaves
8learning modules
24interactive practices
5rapid review questions
50%certificate threshold
Learning target
Build safe recursive CTEs in SQL Server for hierarchies, paths, levels and parent-child traversal while controlling cycles and recursion depth.
Practice progress0 / 24

Complete 12 of 24 practices (50%) and enter your name to unlock the Certificate of Participation.

MODULE 01
🧬

The Anatomy of a Recursive CTE

A recursive CTE has two logical parts: the anchor member produces the starting rows; the recursive member repeatedly joins back to the CTE to find the next generation of rows.

🌳
Start once, repeat the rule

The anchor might select the CEO. The recursive member then finds employees who report to the CEO, then employees who report to those managers, and so on.

Core ideas

  • Anchor = starting row set
  • Recursive member = rule for finding the next level
  • UNION ALL combines anchor and recursive output
  • Recursion stops when an iteration returns no new rows
Core recursive pattern
WITH Org AS
(
    -- Anchor
    SELECT EmployeeID, ManagerID, EmployeeName, 0 AS LevelNo
    FROM dbo.Employee
    WHERE ManagerID IS NULL

    UNION ALL

    -- Recursive member
    SELECT e.EmployeeID,
           e.ManagerID,
           e.EmployeeName,
           o.LevelNo + 1
    FROM dbo.Employee AS e
    JOIN Org AS o
      ON e.ManagerID = o.EmployeeID
)
SELECT *
FROM Org;
✅

A recursive CTE is not magic: define the start, define the next-step relationship, and make sure the process can terminate.

Practice — 3 cases

Practice 1 / Práctica 1
What is the anchor member of a recursive CTE?
Practice 2 / Práctica 2
What does the recursive member do?
Practice 3 / Práctica 3
Which operator typically connects the anchor and recursive members?
MODULE 02
🏢

Walk an Organization Hierarchy

Employee-manager relationships are a classic parent-child structure. Once the relationship is modeled correctly, the recursive CTE can return the entire tree or any subtree.

🌳
Every manager becomes the next parent

After the CEO level is returned, those rows become inputs for finding direct reports. Those direct reports then become inputs for the next iteration.

Core ideas

  • Choose a clear root row or root set
  • Carry LevelNo to make depth visible
  • Return IDs as well as display names
  • Use the same key relationship consistently at every level
Subtree under one manager
DECLARE @RootEmployeeID int = 100;

WITH Org AS
(
    SELECT EmployeeID,
           ManagerID,
           EmployeeName,
           0 AS LevelNo
    FROM dbo.Employee
    WHERE EmployeeID = @RootEmployeeID

    UNION ALL

    SELECT e.EmployeeID,
           e.ManagerID,
           e.EmployeeName,
           o.LevelNo + 1
    FROM dbo.Employee AS e
    JOIN Org AS o
      ON e.ManagerID = o.EmployeeID
)
SELECT *
FROM Org
ORDER BY LevelNo, EmployeeName;
✅

Starting from a selected manager turns the same recursive logic into a reusable subtree query.

Practice — 3 cases

Practice 4 / Práctica 4
In an employee hierarchy, what usually links child rows to parent rows?
Practice 5 / Práctica 5
What does LevelNo usually represent?
Practice 6 / Práctica 6
Why is an org chart a natural recursive CTE problem?
MODULE 03
🧭

Track Depth, Path and Breadcrumbs

A useful hierarchy query often needs more than the rows themselves. Carry metadata through each recursive step: level number, path text, root identifier or accumulated values.

🌳
Carry context as you descend

A category tree becomes much easier to understand when each row includes both its depth and a breadcrumb such as Electronics > Computers > Laptops.

Core ideas

  • Increment depth on every recursive step
  • Carry a root ID when several trees coexist
  • Build paths carefully with explicit data types and lengths
  • Paths can support display and cycle detection
Path and level
WITH CategoryTree AS
(
    SELECT CategoryID,
           ParentCategoryID,
           CategoryName,
           0 AS LevelNo,
           CAST(CategoryName AS varchar(1000)) AS PathText
    FROM dbo.Category
    WHERE ParentCategoryID IS NULL

    UNION ALL

    SELECT c.CategoryID,
           c.ParentCategoryID,
           c.CategoryName,
           p.LevelNo + 1,
           CAST(p.PathText + ' > ' + c.CategoryName AS varchar(1000))
    FROM dbo.Category AS c
    JOIN CategoryTree AS p
      ON c.ParentCategoryID = p.CategoryID
)
SELECT *
FROM CategoryTree;
✅

Depth tells you where the row is; the path tells you how it got there.

Practice — 3 cases

Practice 7 / Práctica 7
Why build a path string in a recursive CTE?
Practice 8 / Práctica 8
What should happen to LevelNo in the recursive member?
Practice 9 / Práctica 9
Which output helps distinguish a root, child and grandchild visually?
MODULE 04
⚙️

Beyond Org Charts: BOMs, Categories and Folder Trees

Recursive CTEs are valuable wherever one row can contain or parent rows of the same logical type. Bills of materials, folder structures and nested categories all repeat the same relationship.

🌳
The relationship repeats, even when the business meaning changes

A manager has employees. A folder has subfolders. An assembly has components. The business nouns differ, but the SQL recursion pattern is the same.

Core ideas

  • Model the parent-child key clearly
  • Carry business measures when needed
  • Use the root to define the requested subtree
  • Validate totals when quantities accumulate across levels
BOM quantity expansion
WITH BOM AS
(
    SELECT ParentPartID,
           ComponentPartID,
           QuantityPer,
           CAST(QuantityPer AS decimal(18,4)) AS ExtendedQty,
           1 AS LevelNo
    FROM dbo.BillOfMaterial
    WHERE ParentPartID = @RootPartID

    UNION ALL

    SELECT b.ParentPartID,
           b.ComponentPartID,
           b.QuantityPer,
           CAST(p.ExtendedQty * b.QuantityPer AS decimal(18,4)),
           p.LevelNo + 1
    FROM dbo.BillOfMaterial AS b
    JOIN BOM AS p
      ON b.ParentPartID = p.ComponentPartID
)
SELECT *
FROM BOM;
✅

Recursive CTEs become especially powerful when they carry business values as well as structural relationships.

Practice — 3 cases

Practice 10 / Práctica 10
Why are bills of materials a recursive problem?
Practice 11 / Práctica 11
What extra value may need to be accumulated through a BOM recursion?
Practice 12 / Práctica 12
Which structure is also naturally recursive?
MODULE 05
🛡️

Cycle Protection and MAXRECURSION

Hierarchical data is only safe when the relationship actually forms a tree or controlled graph. Bad parent-child data can create loops such as A → B → C → A.

🌳
The database can only follow the data you give it

If a node eventually points back to an ancestor, the recursive rule keeps finding work. Production queries need both data-quality checks and a recursion strategy.

Core ideas

  • Validate that nodes cannot become their own ancestors
  • Carry a path of visited IDs when cycle detection is required
  • Use MAXRECURSION deliberately
  • Do not use MAXRECURSION 0 casually in production
Simple cycle guard
WITH Tree AS
(
    SELECT NodeID,
           ParentNodeID,
           CAST('/' + CAST(NodeID AS varchar(20)) + '/' AS varchar(max)) AS VisitPath
    FROM dbo.Node
    WHERE NodeID = @RootNodeID

    UNION ALL

    SELECT n.NodeID,
           n.ParentNodeID,
           CAST(t.VisitPath + CAST(n.NodeID AS varchar(20)) + '/' AS varchar(max))
    FROM dbo.Node AS n
    JOIN Tree AS t
      ON n.ParentNodeID = t.NodeID
    WHERE t.VisitPath NOT LIKE '%/' + CAST(n.NodeID AS varchar(20)) + '/%'
)
SELECT *
FROM Tree
OPTION (MAXRECURSION 200);
✅

MAXRECURSION is a safety boundary, not a substitute for fixing cyclic data.

Practice — 3 cases

Practice 13 / Práctica 13
What is a cycle in hierarchical data?
Practice 14 / Práctica 14
What does SQL Server's MAXRECURSION option control?
Practice 15 / Práctica 15
Why is MAXRECURSION 0 potentially dangerous?
MODULE 06
🔎

Roots, Descendants, Ancestors and Leaves

The same hierarchy can answer different business questions depending on where you anchor it and which direction the relationship is traversed.

🌳
Change the starting point, change the question

Start at a department manager to get all descendants. Reverse the relationship to walk upward and return the chain of managers. Filter for nodes with no children to identify leaves.

Core ideas

  • Anchor determines the root of the requested result
  • Descending traversal follows parent to children
  • Ascending traversal follows child to parent
  • Leaves are nodes with no children
Ancestor chain
WITH Managers AS
(
    SELECT EmployeeID,
           ManagerID,
           EmployeeName,
           0 AS LevelNo
    FROM dbo.Employee
    WHERE EmployeeID = @EmployeeID

    UNION ALL

    SELECT m.EmployeeID,
           m.ManagerID,
           m.EmployeeName,
           c.LevelNo + 1
    FROM dbo.Employee AS m
    JOIN Managers AS c
      ON m.EmployeeID = c.ManagerID
)
SELECT *
FROM Managers;
✅

Recursive direction matters: the same table can be walked downward to descendants or upward to ancestors.

Practice — 3 cases

Practice 16 / Práctica 16
How do you return only descendants of one node?
Practice 17 / Práctica 17
What is a leaf node?
Practice 18 / Práctica 18
Which technique can identify leaf rows after recursion?
MODULE 07
📊

Performance, Indexing and Scale

Recursive CTE syntax can be compact, but execution cost depends on hierarchy size, branching factor, depth, indexing and filtering. A small org chart and a million-node dependency graph are very different workloads.

🌳
Measure how the tree grows

A hierarchy where every node has many children can expand much faster than expected. Good indexes on parent-child keys and a selective root can dramatically change the workload.

Core ideas

  • Index the key used to find children
  • Anchor as selectively as the business question allows
  • Inspect actual row counts per operator
  • Consider alternative models for very large or frequently queried hierarchies
Parent lookup index
CREATE INDEX IX_Employee_ManagerID
ON dbo.Employee (ManagerID)
INCLUDE (EmployeeID, EmployeeName);

-- Then inspect:
SET STATISTICS IO ON;
SET STATISTICS TIME ON;

-- Run recursive query and review Actual Execution Plan.
✅

Recursive CTEs are easy to write; production-ready recursion requires understanding how many rows each level actually creates.

Practice — 3 cases

Practice 19 / Práctica 19
Which columns are especially important to index for a parent-child hierarchy?
Practice 20 / Práctica 20
Why can a recursive CTE be expensive on a large hierarchy?
Practice 21 / Práctica 21
What should you review for a production recursive query?
MODULE 08
🏭

Production Design: When Recursive CTEs Are the Right Tool

Recursive CTEs are excellent for readable, on-demand traversal of moderate hierarchies. But SQL Server also offers hierarchyid, and some systems use closure tables, path enumeration or precomputed hierarchy structures when traversal is extremely frequent or large.

🌳
Choose the model that matches the workload

Recursive CTEs are often the simplest starting point. If hierarchy traversal becomes a central workload with very large scale, compare alternative data models instead of forcing one pattern forever.

Core ideas

  • Use Recursive CTEs for clear parent-child traversal
  • Validate cycles and maximum expected depth
  • Document the root and traversal direction
  • Consider hierarchyid or precomputed models when scale justifies it
Production checklist
1. Confirm the parent-child key
2. Define the anchor/root
3. Define the recursive relationship
4. Carry Level / Path if needed
5. Validate termination
6. Detect or prevent cycles
7. Set an intentional MAXRECURSION strategy
8. Test row counts, IO and execution plan
9. Compare alternative hierarchy models if scale demands it
✅

Recursive CTEs are powerful because they repeat one relationship cleanly; they are safe when termination, data quality and scale are treated as first-class requirements.

Practice — 3 cases

Practice 22 / Práctica 22
When might hierarchyid or another hierarchy model deserve consideration?
Practice 23 / Práctica 23
What is a strong production checklist item before deploying recursion?
Practice 24 / Práctica 24
What is the best overall rule for recursive CTEs?
5-Question Knowledge Check

Can you design a safe recursive CTE?

Open each item after answering it in your own words. The 24 interactive practices above drive certificate progress.

1. What are the two logical members of a recursive CTE?

The anchor member creates the starting rows; the recursive member uses prior rows to find the next level.

2. What normally makes recursion stop?

Recursion stops when the recursive member produces no additional rows, subject to SQL Server's recursion limit.

3. Why can cycles be dangerous?

A cycle can cause the same nodes to be revisited repeatedly, preventing natural termination and producing runaway recursion.

4. What is MAXRECURSION for?

It sets a recursion-depth limit for the statement and acts as a safety boundary.

5. What should you validate before deploying a recursive hierarchy query?

The root, parent-child key, traversal direction, cycle behavior, expected depth, row counts, indexing and actual execution plan.

Recursive CTE Blueprint

A reusable hierarchy pattern

LayerPurpose
AnchorChoose the starting root row or root set
Recursive MemberFind the next parent-child level
ContextCarry Level, Path, Root or accumulated measures
SafetyProtect against cycles and runaway depth
PerformanceIndex hierarchy keys and inspect actual execution behavior

Certificate of Participation

Complete at least 12 of the 24 practice cases (50%) and enter your name.

0 / 24 • 0%
Production note

Recursive CTEs are excellent for clear parent-child traversal, but production safety depends on valid hierarchy data and controlled recursion.