Recursive CTEs help you repeat a query step by step until you get all related data. It is like following a chain of connections one by one.
Recursive CTEs in MySQL
WITH RECURSIVE cte_name (column_list) AS ( -- Anchor member: base query SELECT initial_columns FROM table_name WHERE condition UNION ALL -- Recursive member: query referring to cte_name SELECT next_columns FROM table_name JOIN cte_name ON join_condition WHERE recursive_condition ) SELECT * FROM cte_name;
The anchor member is the starting point of recursion.
The recursive member repeats the query using results from the previous step.
WITH RECURSIVE numbers(n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM numbers WHERE n < 5 ) SELECT * FROM numbers;
WITH RECURSIVE empty_cte AS ( SELECT 1 WHERE FALSE UNION ALL SELECT 2 FROM empty_cte ) SELECT * FROM empty_cte;
WITH RECURSIVE single_node AS ( SELECT 1 AS id UNION ALL SELECT id + 1 FROM single_node WHERE id < 1 ) SELECT * FROM single_node;
WITH RECURSIVE chain AS ( SELECT 1 AS id UNION ALL SELECT id + 1 FROM chain WHERE id < 3 ) SELECT * FROM chain;
This query finds all employees under the top manager, showing their level in the hierarchy.
WITH RECURSIVE employee_hierarchy AS ( -- Anchor member: select the top manager SELECT employee_id, manager_id, employee_name, 1 AS level FROM employees WHERE manager_id IS NULL UNION ALL -- Recursive member: select employees reporting to previous level SELECT e.employee_id, e.manager_id, e.employee_name, eh.level + 1 FROM employees e JOIN employee_hierarchy eh ON e.manager_id = eh.employee_id ) SELECT employee_id, manager_id, employee_name, level FROM employee_hierarchy ORDER BY level, employee_id;
Recursive CTEs run until no new rows are added, so be careful to avoid infinite loops.
Time complexity depends on the depth and branching of recursion; it can grow quickly.
Common mistake: forgetting the anchor member or recursive condition, causing no results or infinite recursion.
Use recursive CTEs when you need to process hierarchical or sequential data inside SQL.
Recursive CTEs let you repeat queries step by step to explore connected data.
They have an anchor part and a recursive part that refers back to the CTE.
Useful for hierarchies, sequences, and tree-like data in databases.
Practice
Solution
Step 1: Understand recursive CTE concept
A recursive CTE runs a base query and then repeatedly runs a recursive part referring back to itself to explore connected data.Step 2: Identify the purpose
This process is mainly used to handle hierarchical or tree-like data, such as organizational charts or folder structures.Final Answer:
To repeatedly execute a query to explore hierarchical or connected data -> Option BQuick Check:
Recursive CTE = hierarchical data exploration [OK]
- Confusing recursive CTEs with temporary tables
- Thinking recursive CTEs speed up all queries
- Assuming recursive CTEs permanently store data
Solution
Step 1: Recall MySQL recursive CTE syntax
MySQL uses the keyword WITH RECURSIVE followed by the CTE name and a query combining an anchor and recursive part with UNION ALL.Step 2: Match syntax options
WITH RECURSIVE cte_name AS (anchor_query UNION ALL recursive_query) SELECT * FROM cte_name; correctly shows this syntax, including UNION ALL and the final SELECT from the CTE.Final Answer:
WITH RECURSIVE cte_name AS (anchor_query UNION ALL recursive_query) SELECT * FROM cte_name; -> Option CQuick Check:
WITH RECURSIVE + UNION ALL = correct syntax [OK]
- Using UNION instead of UNION ALL in recursive part
- Trying to CREATE RECURSIVE TABLE (not valid)
- Misplacing RECURSIVE keyword after CTE name
employees(id, manager_id, name), what will this query return?WITH RECURSIVE subordinates AS ( SELECT id, name FROM employees WHERE id = 2 UNION ALL SELECT e.id, e.name FROM employees e JOIN subordinates s ON e.manager_id = s.id ) SELECT * FROM subordinates;
Solution
Step 1: Analyze anchor query
The anchor selects the employee with id = 2 as the starting point.Step 2: Analyze recursive part
The recursive part joins employees whose manager_id matches the current subordinates' id, thus finding direct reports, then their reports, and so on.Step 3: Understand final output
The query returns employee 2 and all employees reporting to them directly or indirectly.Final Answer:
All employees who report directly or indirectly to employee with id 2 -> Option AQuick Check:
Recursive join on manager_id finds all subordinates [OK]
- Confusing manager and subordinate roles
- Thinking it returns only direct reports
- Assuming syntax error due to anchor query presence
WITH RECURSIVE cte AS ( SELECT id FROM items WHERE parent_id IS NULL UNION SELECT i.id FROM items i JOIN cte ON i.parent_id = cte.id ) SELECT * FROM cte;
Solution
Step 1: Check recursive CTE syntax
Recursive CTEs require UNION ALL to combine anchor and recursive parts to avoid duplicate elimination.Step 2: Understand effect of UNION vs UNION ALL
Using UNION removes duplicates each iteration, which can cause infinite recursion or incorrect results in recursive queries.Final Answer:
Missing UNION ALL causes infinite recursion or wrong results -> Option DQuick Check:
Recursive CTEs must use UNION ALL [OK]
- Using UNION instead of UNION ALL in recursive CTE
- Assuming NULL vs 0 matters for recursion logic
- Thinking JOIN type affects recursion correctness
employees(id, manager_id, name). Which recursive CTE query correctly finds all managers up the chain for employee with id 5?Solution
Step 1: Understand the goal
We want to find all managers (ancestors) of employee 5, moving up the chain via manager_id.Step 2: Analyze join condition
To move up, join employees where employee id matches the manager_id of current ancestor (e.id = a.manager_id).Step 3: Check anchor and recursive parts
Anchor selects employee 5; recursive part finds their manager, then that manager's manager, etc.Final Answer:
WITH RECURSIVE ancestors AS (SELECT id, manager_id, name FROM employees WHERE id = 5 UNION ALL SELECT e.id, e.manager_id, e.name FROM employees e JOIN ancestors a ON e.id = a.manager_id) SELECT * FROM ancestors WHERE id != 5; -> Option AQuick Check:
Join on e.id = a.manager_id moves up hierarchy [OK]
- Reversing join condition to move down instead of up
- Using UNION instead of UNION ALL causing errors
- Starting anchor with manager_id = 5 instead of id = 5
Ready to prove it?
Pass the test and this pattern moves unknown
