Backend Development › Relational Databases & SQL
Recursive CTE
Querying hierarchies and graphs, like org charts or category trees.
Also known as: recursive cte, recursive common table expression, recursive query
A recursive CTE is a common table expression that can reference its own previous result, letting one query walk a hierarchy or graph — an org chart, a bill of materials, a thread of comments, a category tree. It replaces code that would otherwise loop in the application.
A recursive CTE has two parts joined by UNION [ALL]:
- a base case (anchor) — the starting rows;
- a recursive term — joins the CTE’s own result back to the table to get the next level.
WITH RECURSIVE tree AS (
SELECT id, name, manager_id FROM employees WHERE manager_id IS NULL -- base
UNION ALL
SELECT e.id, e.name, e.manager_id
FROM employees e JOIN tree t ON e.manager_id = t.id -- recurse
)
SELECT * FROM tree;
Execution repeats the recursive term until it returns no new rows, accumulating the whole hierarchy level by level.
The classic mistakes:
- No termination guarantee. If the data contains a cycle, the recursion never stops. Add a depth limit or track visited nodes to be safe.
UNION ALLvsUNION.UNION ALLkeeps duplicates and is faster;UNIONdeduplicates but costs more and can accidentally hide intended repeats. Choose deliberately.- Expecting great performance on deep recursion. Each iteration scans/joins; deep or wide hierarchies get expensive. Index the join column (
manager_id) and consider materialised paths for frequently queried trees. - Recursion in the application instead. A loop calling the database once per level is N+1 round trips; the recursive CTE does it in one query. Prefer the CTE for tree reads.
- Assuming full cycle-safety. Even a depth limit changes results silently if it’s hit; validate the data or report truncation.
When to use it: for querying variable-depth hierarchical data in one statement — ancestors/descendants, path building, transitive closure. For simple one-level self-joins, a plain self-join is simpler. For heavy graph traversal, a graph database is the specialised tool. See CTEs.