Recursive Query
Categories:
The general structure of the Postgres recursive query contains,
- Non-recursive select statement
- Union or union all
- Recursive select statement
WITH RECURSIVE name_cte AS (
SELECT statement /* non-recursive statement */
UNION [ALL]
SELECT statement /*recursive statement referencing the above select statement */
)
SELECT * FROM name_cte;
How does a Postres recursive query work
- Evaluate non-recursive statements and creates a temporary table
- Evaluate recursive terms and add them to the temporary table
- Repeat step 2 till the working table is empty.
The difference between union and union all is that union all allows duplicates union will not allow any duplicates.
Example
First 10 natural numbers
WITH RECURSIVE tens AS (
SELECT 1 as n
UNION ALL
SELECT n+1 FROM tens
)
SELECT n FROM tens limit 10;
This is the basic example of Postres recursive query which prints the first 10 natural numbers.
Postres recursive query to find factorial of a natural number:
WITH RECURSIVE fact (n, factorial)
AS (
SELECT 1 as n, 5 as factorial
union all
SELECT n+1, factorial*n FROM fact where n < 5
)
SELECT * FROM fact;
This query outputs two tables one with the first five natural numbers and the other table with calculations that are performed to find the factorial.
We can print only the last row but here we can see how the iteration and calculation take place.
Postres recursive query to print Fibonacci series:
WITH RECURSIVE fibb
AS (
SELECT 1::bigint as n, 0::bigint as a, 1::bigint as b
UNION ALL
SELECT n+1, b as a, (a+b) as b FROM fibb
)
SELECT b FROM fibb limit 10;
This prints the Fibonacci series up to 10.
Organizational hierarchy
With the help of Postgres recursive query, we can find the organizational hierarchy:
To create a table:
INSERT INTO employees (
employee_id,
full_name,
manager_id
)
VALUES
(1, 'Abhi', NULL),
(2, 'Bhargav', 1),
(3, 'Chay', 1),
(4, 'Dravid', 1),
(5, 'Erin', 1),
(6, 'Ford', 2),
(7, 'Gagan', 2),
(8, 'Harry', 3),
(9, 'Isaac', 3),
(10, 'Jack', 4),
(11, 'Kiran', 5);
Abhi is the boss, he will be on the first level. Bhargav, Chay, Dravid, Erin are in the next level and the rest of them will be the last level.
Query:
WITH RECURSIVE subordinates AS (
SELECT employee_id, manager_id, full_name, 0 as level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.manager_id, e.full_name, level+1
FROM employees e
INNER JOIN subordinates s ON s.employee_id = e.manager_id
)
SELECT * FROM subordinates;
The output will be: