Navigating Hierarchies with Recursive CTEs
In this lesson, you will learn how to traverse parent-child relationships stored within a single table using Recursive Common Table Expressions (CTEs).
When working with embedded databases like SQLite, you often store tree-structured data—such as organizational charts, category trees, or file systems—in a single table where each row contains a reference to its parent. Because the depth of these structures is often unknown or variable, a standard JOIN is insufficient. This is where the Recursive CTE comes in.
The Anatomy of a Recursive CTE
A Recursive CTE consists of two main parts joined by a UNION ALL operator:
- The Anchor Member: An initial query that identifies the starting point of your hierarchy (e.g., the "root" node).
- The Recursive Member: A query that references the CTE name itself, effectively "joining" the existing results back to the source table to find the next level of the hierarchy.
Practical Example
Imagine a categories table where each row has an id, a name, and a parent_id. To find the entire path from a specific sub-category back to the root, you would use a query like this:
WITH RECURSIVE CategoryPath AS (
-- Anchor: Start with the specific category
SELECT id, name, parent_id
FROM categories
WHERE id = 10
UNION ALL
-- Recursive: Join the table to find the parent of the previous result
SELECT c.id, c.name, c.parent_id
FROM categories c
INNER JOIN CategoryPath cp ON c.id = cp.parent_id
)
SELECT * FROM CategoryPath;
How it Works
The database engine executes the anchor member first, storing those rows in a temporary result set. Then, it iteratively runs the recursive member. In each iteration, it uses the rows found in the previous step to look up the next layer of parents. This continues until the recursive member returns no more matches.
Because we are working in an embedded environment, keep in mind that recursion depth is often limited by the database engine's configuration. Always ensure your data structure is a true tree (avoiding circular references) to prevent infinite loops.
Key Takeaway: Recursive CTEs allow you to traverse unpredictable tree depths by iteratively joining a table to its own previous result set via a UNION ALL construct.