A Recursive CTE (Common Table Expression) is a SQL query that refers to itself to repeatedly execute and build a result set. It is useful for tasks like traversing hierarchical or graph data.
Click to reveal answer
intermediate
How does a Recursive CTE work for graph traversal?
It starts with a base query selecting initial nodes, then repeatedly joins the CTE to the graph edges to find connected nodes until no new nodes are found.
Click to reveal answer
beginner
What are the two main parts of a Recursive CTE?
1. Anchor member: the base query that runs first. 2. Recursive member: the query that references the CTE itself to find connected rows.
Click to reveal answer
intermediate
Why is it important to have a termination condition in a Recursive CTE?
Without a termination condition, the recursion would run forever. The query stops when no new rows are added in the recursive step.
Click to reveal answer
intermediate
Give a simple example of a Recursive CTE to find all reachable nodes from a start node in a graph.
WITH RECURSIVE reachable_nodes AS (
SELECT id FROM nodes WHERE id = 1 -- anchor member
UNION
SELECT e.target_id FROM edges e JOIN reachable_nodes r ON e.source_id = r.id -- recursive member
) SELECT * FROM reachable_nodes;
Click to reveal answer
What does the anchor member of a Recursive CTE do?
ADefines the starting point of recursion
BTerminates the recursion
CJoins tables without recursion
DDeletes rows from the table
✗ Incorrect
The anchor member defines the initial rows from which recursion begins.
In graph traversal using Recursive CTE, what does the recursive member typically do?
ASelects unrelated rows
BJoins the CTE to graph edges to find connected nodes
CDeletes visited nodes
DCreates new tables
✗ Incorrect
The recursive member joins the CTE to edges to find nodes connected to already found nodes.
What happens if a Recursive CTE has no termination condition?
AIt runs forever causing an error or timeout
BIt returns an empty result
CIt runs once and stops
DIt automatically optimizes
✗ Incorrect
Without termination, recursion never stops, causing infinite loops or errors.
Which keyword is used to define a Recursive CTE in PostgreSQL?
AWITH LOOP
BRECURSIVE SELECT
CWITH RECURSIVE
DCTE RECURSIVE
✗ Incorrect
PostgreSQL uses 'WITH RECURSIVE' to start a recursive CTE.
What kind of data is Recursive CTE especially useful for?
AUnrelated random data
BFlat tables without relationships
CSingle row tables
DHierarchical or graph data
✗ Incorrect
Recursive CTEs are designed to handle hierarchical or graph-like data structures.
Explain how a Recursive CTE can be used to traverse a graph in SQL.
Think about starting points and how to find connected nodes repeatedly.
You got /3 concepts.
Describe the importance of the termination condition in a Recursive CTE.
What happens if recursion never stops?
You got /3 concepts.
Practice
(1/5)
1. What is the main purpose of using a WITH RECURSIVE clause in PostgreSQL when working with graph data?
easy
A. To optimize query performance by indexing graph nodes
B. To create temporary tables for storing graph data
C. To repeatedly execute a query that references itself to explore connected nodes
D. To join two unrelated tables without conditions
Solution
Step 1: Understand the purpose of recursive CTEs
Recursive CTEs allow a query to call itself repeatedly, which is useful for exploring connected data like graph nodes.
Step 2: Identify the correct use case
Using WITH RECURSIVE lets you traverse graph structures step-by-step by referencing the CTE inside itself.
Final Answer:
To repeatedly execute a query that references itself to explore connected nodes -> Option C
Quick Check:
Recursive CTE = self-referencing query [OK]
Hint: Recursive CTEs repeat queries to explore connected data [OK]
Common Mistakes:
Confusing recursive CTE with temporary tables
Thinking it automatically optimizes performance
Using it for unrelated table joins
2. Which of the following is the correct basic syntax to start a recursive CTE named path in PostgreSQL?
easy
A. WITH path RECURSIVE AS (SELECT ... UNION ALL SELECT ... FROM path ...)
B. CREATE RECURSIVE TABLE path AS SELECT ...
C. SELECT RECURSIVE * FROM path
D. WITH RECURSIVE path AS (SELECT ... UNION ALL SELECT ... FROM path ...)
Solution
Step 1: Recall the syntax for recursive CTEs
The correct syntax starts with WITH RECURSIVE cte_name AS ( ... ), where the CTE references itself inside.
Step 2: Match the syntax options
WITH RECURSIVE path AS (SELECT ... UNION ALL SELECT ... FROM path ...) correctly uses WITH RECURSIVE path AS (SELECT ... UNION ALL SELECT ... FROM path ...). Other options misuse keywords or order.
Final Answer:
WITH RECURSIVE path AS (SELECT ... UNION ALL SELECT ... FROM path ...) -> Option D
Quick Check:
WITH RECURSIVE + CTE name + self-reference [OK]
Hint: Start with WITH RECURSIVE cte_name AS (...) [OK]
Common Mistakes:
Swapping RECURSIVE and CTE name order
Using CREATE instead of WITH
Omitting UNION ALL between parts
3. Given the table edges(source INT, target INT) with data: (1, 2), (2, 3), (3, 4), (2, 5) What will the following query return?
WITH RECURSIVE path AS (SELECT source, target FROM edges WHERE source = 1 UNION ALL SELECT e.source, e.target FROM edges e JOIN path p ON e.source = p.target) SELECT * FROM path ORDER BY source, target;
medium
A. Rows: (1,2), (2,3), (2,5), (3,4)
B. Rows: (1,2), (2,3), (3,4)
C. Rows: (1,2), (2,5)
D. Empty result
Solution
Step 1: Identify the anchor and recursive parts
The anchor selects edges where source=1: (1,2). The recursive part joins edges where source matches previous target.
Step 2: Trace recursive expansion
From (1,2), next edges with source=2 are (2,3) and (2,5). From (2,3), next edge with source=3 is (3,4). No further edges from 5 or 4.
Final Answer:
Rows: (1,2), (2,3), (2,5), (3,4) -> Option A
Quick Check:
Recursive join expands all reachable edges [OK]
Hint: Follow edges from start node stepwise [OK]
Common Mistakes:
Ignoring multiple edges from same source
Stopping recursion too early
Misordering results
4. Consider this recursive CTE:
WITH RECURSIVE path(node) AS (SELECT 1 UNION ALL SELECT node + 1 FROM path WHERE node < 3) SELECT * FROM path;
What is wrong if this query runs forever without stopping?
medium
A. Not selecting from the CTE in the final SELECT
B. Missing a proper termination condition in the recursive part
C. Using UNION instead of UNION ALL
D. Incorrect anchor query syntax
Solution
Step 1: Analyze the recursive condition
The recursive part adds 1 to node while node < 3, but due to UNION ALL accumulating duplicates of rows satisfying the condition, recursion continues indefinitely.
Step 2: Identify why it loops infinitely
If the termination condition is incorrect or not reached, recursion never stops. Here, the condition is present but ineffective against duplicates, causing infinite loop.
Final Answer:
Missing a proper termination condition in the recursive part -> Option B
Quick Check:
Infinite recursion = no stop condition [OK]
Hint: Check recursive WHERE clause stops recursion [OK]
Common Mistakes:
Confusing UNION and UNION ALL effects
Ignoring anchor query correctness
Forgetting to select from CTE
5. You have a table employees(id INT, manager_id INT) representing a company hierarchy. How would you write a recursive CTE to find all employees under manager with id = 10, including indirect reports?
hard
A.
WITH RECURSIVE subordinates AS (
SELECT id FROM employees WHERE manager_id = 10
UNION ALL
SELECT e.id FROM employees e JOIN subordinates s ON e.manager_id = s.id
) SELECT * FROM subordinates;
B.
WITH RECURSIVE subordinates AS (
SELECT id FROM employees WHERE id = 10
UNION ALL
SELECT e.id FROM employees e JOIN subordinates s ON e.id = s.manager_id
) SELECT * FROM subordinates;
C.
WITH RECURSIVE subordinates AS (
SELECT id FROM employees WHERE manager_id = 10
UNION ALL
SELECT e.manager_id FROM employees e JOIN subordinates s ON e.id = s.id
) SELECT * FROM subordinates;
D.
WITH RECURSIVE subordinates AS (
SELECT id FROM employees WHERE manager_id = 10
UNION ALL
SELECT e.id FROM employees e JOIN subordinates s ON e.id = s.manager_id
) SELECT * FROM subordinates;
Solution
Step 1: Identify the anchor query
The anchor selects employees directly reporting to manager 10: WHERE manager_id = 10.
Step 2: Understand the recursive join
The recursive part joins employees whose manager_id matches any previously found employee id, thus finding indirect reports.
Final Answer:
WITH RECURSIVE subordinates AS ( SELECT id FROM employees WHERE manager_id = 10 UNION ALL SELECT e.id FROM employees e JOIN subordinates s ON e.manager_id = s.id ) SELECT * FROM subordinates; -> Option A
Quick Check:
Join on e.manager_id = s.id to find subordinates [OK]
Hint: Join on manager_id = previous employee id to find reports [OK]
Common Mistakes:
Swapping join conditions (id vs manager_id)
Starting anchor with wrong WHERE clause
Selecting wrong columns in recursive part
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.