Common Table Expressions (CTEs) are great for cleaning up your code. But Recursive CTEs are a whole different beast. They allow you to reference the CTE itself inside its own definition.
It sounds like infinite loop territory (and it can be!), but when tamed, it unlocks superpowers like:
- Traversing organizational charts (who reports to whom?)
- Generating calendar dates to fill reporting gaps.
- Finding paths in graph data (flight connections, network routes).
The Anatomy of WITH RECURSIVE
A recursive CTE always has three parts:
- The Anchor Member: The starting point (non-recursive).
- The Recursive Member: The query that references the CTE name.
- The Termination Condition: A
WHEREclause that eventually stops the recursion.
WITH RECURSIVE my_cte AS (
-- 1. Anchor Member
SELECT 1 AS n
UNION ALL
-- 2. Recursive Member
SELECT n + 1
FROM my_cte
WHERE n < 10 -- 3. Termination Condition
)
SELECT * FROM my_cte;
Use Case 1: Generating Data
Sometimes you need a row for every day in a month, even if your transaction table has missing dates. Recursive CTEs are the standard way to do this in PostgreSQL and SQLite.
Use Case 2: Traversing Hierarchies (Org Charts)
This is the classic textbook example. Imagine an employees table where each employee has a manager_id. How do you find the full chain of command for everyone?
How it works:
- Validating the Anchor: It finds "Big Boss". Level = 0.
- Iteration 1: It joins "Big Boss" (ID 1) to find his direct reports (VP Sales, VP Eng). Level = 1.
- Iteration 2: It finds reports of the VPs. Level = 2.
- Stop: When no more employees are found for the join, the recursion stops.
Pitfalls to Avoid
The Infinite Loop
If you forget the WHERE clause or your logic creates a cycle (A manages B, B manages A), the query will run forever (or until the database kills it).
Safety Tip: You can strictly limit depth as a failsafe:
WHERE n < 100 -- Hard limit
Performance on Large Trees
Recursive CTEs process typically row-by-row or level-by-level. For massive graphs (millions of nodes), specialized graph databases might be faster. But for most standard business hierarchies, it works perfectly.
Conclusion
WITH RECURSIVE is one of those features that separates SQL users from SQL masters. It turns complex application-level logic (loops and trees) into a single, elegant database query.