SQL Practice Logo

SQLPractice Online

Recursive CTEs: Mistakes

Module: Subqueries & CTEs

WITH RECURSIVE tree AS (

SELECT id, parent_id FROM nodes WHERE id = 1

UNION ALL

SELECT n.id, n.parent_id FROM nodes n JOIN tree t ON n.parent_id = t.id

-- Missing termination!

)

SELECT * FROM tree;

WITH RECURSIVE tree AS (

SELECT id, parent_id, 0 AS level FROM nodes WHERE id = 1

UNION ALL

SELECT n.id, n.parent_id, t.level + 1 FROM nodes n JOIN tree t ON n.parent_id = t.id

WHERE t.level < 10 -- Termination condition

)

SELECT * FROM tree;

Without termination condition, recursive CTE continues forever if data has cycles or is very deep. Always add WHERE level < N or similar limit. Database will eventually hit MAXRECURSION limit and error.

Always track level/depth and add WHERE level < reasonable_max

Critical

Infinite recursion - query never stops

WITH RECURSIVE paths AS (

SELECT node_id, ARRAY[node_id] AS path FROM graph WHERE node_id = 1

UNION ALL

SELECT g.target_id, p.path || g.target_id FROM graph g JOIN paths p ON g.source_id = p.node_id

-- No cycle detection!

)

SELECT * FROM paths;

WITH RECURSIVE paths AS (

SELECT node_id, ARRAY[node_id] AS path FROM graph WHERE node_id = 1

UNION ALL

SELECT g.target_id, p.path || g.target_id FROM graph g JOIN paths p ON g.source_id = p.node_id

WHERE NOT g.target_id = ANY(p.path) -- Prevent cycles

)

SELECT * FROM paths;

Graph data (friendships, links) can have cycles: A→B→C→A. Without cycle detection, recursion loops forever. Track visited nodes in path array and check before adding.

For graphs, always track path and check: WHERE NOT new_node = ANY(path)

Critical

Infinite loop in cyclic graphs

WITH RECURSIVE org AS (

SELECT * FROM employees WHERE manager_id IS NULL

UNION -- Wrong! Should be UNION ALL

SELECT e.* FROM employees e JOIN org o ON e.manager_id = o.id