A Recursive CTE (Common Table Expression) is a SQL query that refers to itself to process hierarchical or tree-structured data, allowing you to retrieve parent-child relationships in a single query.
Click to reveal answer
beginner
What are the two main parts of a Recursive CTE?
1. Anchor member: The initial query that returns the root rows. 2. Recursive member: The query that references the CTE itself to find child rows, repeating until no more children are found.
Click to reveal answer
intermediate
Why use Recursive CTEs instead of multiple queries for hierarchical data?
Recursive CTEs simplify querying hierarchical data by using a single query to traverse all levels, improving readability and performance compared to running multiple queries or loops.
Click to reveal answer
intermediate
In a Recursive CTE, what stops the recursion from running forever?
The recursion stops when the recursive member query returns no new rows, meaning there are no more child records to process.
Click to reveal answer
advanced
Example: What does this Recursive CTE do?
WITH RECURSIVE EmployeeHierarchy AS ( SELECT EmployeeID, ManagerID, 1 AS Level FROM Employees WHERE ManagerID IS NULL UNION ALL SELECT e.EmployeeID, e.ManagerID, eh.Level + 1 FROM Employees e JOIN EmployeeHierarchy eh ON e.ManagerID = eh.EmployeeID) SELECT * FROM EmployeeHierarchy;
This query builds a hierarchy of employees starting from top-level managers (where ManagerID is NULL) and recursively finds all employees under each manager, adding a 'Level' column to show depth in the hierarchy.
Click to reveal answer
What keyword starts a Recursive CTE in SQL?
ARECURSIVE CTE
BWITH RECURSIVE
CSELECT RECURSIVE
DSTART RECURSIVE
✗ Incorrect
Recursive CTEs begin with the keyword 'WITH RECURSIVE' followed by the CTE name and query.
In a Recursive CTE, what does the anchor member do?
ADefines the base rows to start recursion
BJoins tables together
CLimits the number of recursion levels
DDeletes duplicate rows
✗ Incorrect
The anchor member defines the starting rows, usually the root nodes in hierarchical data.
How does a Recursive CTE know when to stop recursion?
AWhen the recursive query returns no new rows
BWhen a maximum recursion level is reached
CWhen a timeout occurs
DWhen the user cancels the query
✗ Incorrect
Recursion stops naturally when the recursive member returns no new rows to add.
Which SQL clause is used to combine the anchor and recursive parts in a Recursive CTE?
AORDER BY
BJOIN
CGROUP BY
DUNION ALL
✗ Incorrect
UNION ALL combines the anchor member and recursive member results in Recursive CTEs.
What kind of data is best suited for Recursive CTEs?
AFlat tabular data without relationships
BRandom unstructured text
CHierarchical or tree-structured data
DSingle row data
✗ Incorrect
Recursive CTEs are designed to handle hierarchical data like organizational charts or folder trees.
Explain how a Recursive CTE works to retrieve hierarchical data.
Think about starting from the top and finding children step by step.
You got /4 concepts.
Describe a real-life example where you would use a Recursive CTE.
Consider any data that looks like a tree or hierarchy.
You got /4 concepts.
Practice
(1/5)
1. What is the main purpose of a RECURSIVE CTE in SQL when working with hierarchical data?
easy
A. To speed up simple SELECT queries without joins
B. To repeatedly query connected rows to explore hierarchical relationships
C. To create temporary tables for storing unrelated data
D. To update multiple tables at once
Solution
Step 1: Understand the role of recursive CTEs
Recursive CTEs allow querying hierarchical or connected data by repeatedly joining rows to find related entries.
Step 2: Compare options with this purpose
Only To repeatedly query connected rows to explore hierarchical relationships describes this repeated querying of connected rows to explore hierarchies.
Final Answer:
To repeatedly query connected rows to explore hierarchical relationships -> Option B
Hint: Recursive CTEs repeatedly join related rows to explore hierarchies [OK]
Common Mistakes:
Confusing recursive CTEs with simple temporary tables
Thinking recursive CTEs speed up unrelated queries
Assuming recursive CTEs update data
2. Which of the following is the correct syntax to start a recursive CTE named OrgChart in SQL?
easy
A. DECLARE RECURSIVE OrgChart BEGIN ... END
B. CREATE RECURSIVE TABLE OrgChart AS ( ... )
C. SELECT RECURSIVE OrgChart FROM ...
D. WITH RECURSIVE OrgChart AS ( ... )
Solution
Step 1: Recall recursive CTE syntax
The correct way to start a recursive CTE is using WITH RECURSIVE Name AS ( ... ).
Step 2: Check each option
WITH RECURSIVE OrgChart AS ( ... ) matches the correct syntax. Options A, B, and C use invalid or unrelated SQL commands.
Final Answer:
WITH RECURSIVE OrgChart AS ( ... ) -> Option D
Quick Check:
Recursive CTE starts with WITH RECURSIVE [OK]
Hint: Recursive CTE always starts with WITH RECURSIVE [OK]
Common Mistakes:
Using CREATE instead of WITH for CTEs
Trying to SELECT RECURSIVE directly
Using DECLARE which is for procedural code
3. Given the table Employees(id, name, manager_id) where manager_id references id, what will the following query return?
WITH RECURSIVE Subordinates AS (
SELECT id, name, manager_id FROM Employees WHERE id = 2
UNION ALL
SELECT e.id, e.name, e.manager_id FROM Employees e
JOIN Subordinates s ON e.manager_id = s.id
)
SELECT * FROM Subordinates;
medium
A. All employees who report directly or indirectly to employee with id 2
B. Only the employee with id 2
C. All employees who have no manager
D. All employees in the company
Solution
Step 1: Analyze the base query
The base query selects the employee with id = 2.
Step 2: Analyze the recursive part
The recursive part joins employees whose manager_id matches any id found so far, thus finding all subordinates under employee 2.
Final Answer:
All employees who report directly or indirectly to employee with id 2 -> Option A
Quick Check:
Recursive join finds all subordinates [OK]
Hint: Recursive CTE with join on manager_id finds all subordinates [OK]
Common Mistakes:
Thinking it returns only the base employee
Assuming it returns employees without managers
Believing it returns all employees regardless
4. Identify the error in this recursive CTE that tries to list all descendants of a node in a tree:
WITH RECURSIVE Descendants AS (
SELECT id, parent_id FROM Tree WHERE id = 1
UNION ALL
SELECT t.id, t.parent_id FROM Tree t
JOIN Descendants d ON t.id = d.parent_id
)
SELECT * FROM Descendants;
medium
A. The JOIN condition should be ON t.parent_id = d.id, not t.id = d.parent_id
B. The base query should select from Descendants, not Tree
C. Recursive CTEs cannot use JOINs
D. The recursive part should use UNION, not UNION ALL
Solution
Step 1: Understand the tree relationship
Each node's parent_id points to its parent. To find descendants, join where child's parent_id equals parent's id.
Step 2: Check the JOIN condition
The query incorrectly joins on t.id = d.parent_id. It should be t.parent_id = d.id to find children of current nodes.
Final Answer:
The JOIN condition should be ON t.parent_id = d.id, not t.id = d.parent_id -> Option A
Quick Check:
Join child parent_id to parent id [OK]
Hint: Join child's parent_id to parent's id to find descendants [OK]
Common Mistakes:
Reversing join condition columns
Using base query from recursive CTE itself
Thinking recursive CTEs can't use JOIN
Confusing UNION and UNION ALL usage
5. You have a parts list table Parts(id, name, parent_part_id) representing assemblies and subassemblies. Write a recursive CTE query to find the full hierarchy of parts under part with id = 10, including the root part itself, and show the level (depth) of each part in the hierarchy starting at 0 for the root. Which query is correct?
hard
A. WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id FROM Parts WHERE parent_part_id IS NULL
UNION ALL
SELECT p.id, p.name, p.parent_part_id FROM Parts p
JOIN PartHierarchy ph ON p.id = ph.parent_part_id
)
SELECT * FROM PartHierarchy WHERE id = 10;
B. WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id, 1 AS level FROM Parts WHERE id = 10
UNION ALL
SELECT p.id, p.name, p.parent_part_id, ph.level - 1 FROM Parts p
JOIN PartHierarchy ph ON p.id = ph.parent_part_id
)
SELECT * FROM PartHierarchy;
C. WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id, 0 AS level FROM Parts WHERE id = 10
UNION ALL
SELECT p.id, p.name, p.parent_part_id, ph.level + 1 FROM Parts p
JOIN PartHierarchy ph ON p.parent_part_id = ph.id
)
SELECT * FROM PartHierarchy;
D. WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id, 0 AS level FROM Parts WHERE id = 10
UNION ALL
SELECT p.id, p.name, p.parent_part_id, ph.level + 1 FROM Parts p
JOIN PartHierarchy ph ON p.id = ph.parent_part_id
)
SELECT * FROM PartHierarchy;
Solution
Step 1: Identify the base case and level
The base query selects the root part with id=10 and sets level to 0.
Step 2: Check the recursive join and level increment
The recursive part joins parts where parent_part_id matches current part's id, and increments level by 1 to track depth.
Step 3: Verify options
WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id, 0 AS level FROM Parts WHERE id = 10
UNION ALL
SELECT p.id, p.name, p.parent_part_id, ph.level + 1 FROM Parts p
JOIN PartHierarchy ph ON p.parent_part_id = ph.id
)
SELECT * FROM PartHierarchy; correctly implements this logic. WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id, 1 AS level FROM Parts WHERE id = 10
UNION ALL
SELECT p.id, p.name, p.parent_part_id, ph.level - 1 FROM Parts p
JOIN PartHierarchy ph ON p.id = ph.parent_part_id
)
SELECT * FROM PartHierarchy; has wrong join direction and decrements level. WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id FROM Parts WHERE parent_part_id IS NULL
UNION ALL
SELECT p.id, p.name, p.parent_part_id FROM Parts p
JOIN PartHierarchy ph ON p.id = ph.parent_part_id
)
SELECT * FROM PartHierarchy WHERE id = 10; starts from root parts but filters later, missing the correct root. WITH RECURSIVE PartHierarchy AS (
SELECT id, name, parent_part_id, 0 AS level FROM Parts WHERE id = 10
UNION ALL
SELECT p.id, p.name, p.parent_part_id, ph.level + 1 FROM Parts p
JOIN PartHierarchy ph ON p.id = ph.parent_part_id
)
SELECT * FROM PartHierarchy; has wrong join direction.
Final Answer:
The query with base WHERE id=10, level 0, JOIN p.parent_part_id=ph.id, level+1 -> Option C
Quick Check:
Join on child.parent_part_id = parent.id, level + 1 [OK]
Hint: Join child.parent_part_id = parent.id and increment level [OK]
Common Mistakes:
Reversing join condition (parent to child)
Starting level at 1 or decrementing level
Filtering after recursion instead of base case
Using wrong root selection
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.