ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

PL/pgSQL Recursive Hierarchy Traversal

PL/pgSQL

Goal -- WPM

Ready
Exercise Algorithm Area
1CREATE TABLE employees (
2employee_id SERIAL PRIMARY KEY,
3name VARCHAR(100),
4manager_id INTEGER REFERENCES employees(employee_id)
5);
6
7-- Sample Data (for illustration)
8-- INSERT INTO employees (name, manager_id) VALUES ('CEO', NULL);
9-- INSERT INTO employees (name, manager_id) VALUES ('VP Sales', 1);
10-- INSERT INTO employees (name, manager_id) VALUES ('Director Eng', 1);
11-- INSERT INTO employees (name, manager_id) VALUES ('Manager Sales A', 2);
12-- INSERT INTO employees (name, manager_id) VALUES ('Manager Sales B', 2);
13-- INSERT INTO employees (name, manager_id) VALUES ('Engineer 1', 3);
14
15CREATE OR REPLACE FUNCTION get_all_descendants(
16p_employee_id INTEGER
17) RETURNS TABLE(employee_id INTEGER, name VARCHAR(100)) AS $$
18BEGIN
19RETURN QUERY
20WITH RECURSIVE employee_hierarchy AS (
21-- Anchor member: Select the starting employee
22SELECT
23e.employee_id,
24e.name,
25e.manager_id
26FROM
27employees e
28WHERE
29e.employee_id = p_employee_id
30
31UNION ALL
32
33-- Recursive member: Select direct reports of employees in the hierarchy
34SELECT
35e.employee_id,
36e.name,
37e.manager_id
38FROM
39employees e
40JOIN
41employee_hierarchy eh ON e.manager_id = eh.employee_id
42)
43-- Select all employees from the hierarchy, excluding the starting employee itself
44SELECT
45eh.employee_id,
46eh.name
47FROM
48employee_hierarchy eh
49WHERE
50eh.employee_id != p_employee_id
51ORDER BY
52eh.employee_id;
53END;
54$$ LANGUAGE plpgsql;
Algorithm description viewbox

PL/pgSQL Recursive Hierarchy Traversal

Algorithm description:

This PL/pgSQL function efficiently retrieves all descendants of a given employee in an organizational hierarchy. It leverages a recursive Common Table Expression (CTE) to traverse the `employees` table, starting from a specified `p_employee_id`. The CTE first selects the starting employee (anchor member) and then recursively joins with the `employees` table to find direct reports (recursive member). The final query returns all identified descendants, excluding the initial employee. This is a standard pattern for querying tree-like structures within relational databases, essential for reporting, access control, or organizational analysis.

Algorithm explanation:

The `get_all_descendants` function uses a recursive CTE named `employee_hierarchy`. The anchor member selects the employee specified by `p_employee_id`. The recursive member then joins `employees` with the `employee_hierarchy` CTE on `e.manager_id = eh.employee_id`, effectively finding all direct reports of employees already in the hierarchy. This process repeats until no new direct reports are found. The final `SELECT` statement retrieves all employees from the `employee_hierarchy` CTE, filtering out the starting employee (`p_employee_id`) itself, and orders them by `employee_id`. The time complexity of a recursive CTE can vary significantly depending on the depth and breadth of the hierarchy and the indexing on `manager_id`. In the worst case, it can be exponential, but with proper indexing, it's often closer to O(N), where N is the number of nodes in the subtree being traversed. Space complexity is O(D), where D is the maximum recursion depth, to store intermediate results.

Pseudocode:

CREATE TABLE employees (employee_id, name, manager_id)

FUNCTION get_all_descendants(start_employee_id):
  WITH RECURSIVE employee_hierarchy AS (
    -- Anchor member
    SELECT employee_id, name, manager_id
    FROM employees
    WHERE employee_id = start_employee_id

    UNION ALL

    -- Recursive member
    SELECT e.employee_id, e.name, e.manager_id
    FROM employees e
    JOIN employee_hierarchy eh ON e.manager_id = eh.employee_id
  )
  SELECT employee_id, name
  FROM employee_hierarchy
  WHERE employee_id != start_employee_id
  ORDER BY employee_id
END FUNCTION