Skip to content
Reliable Data Engineering
Practice problem hard recursive-ctehierarchygraphs
Solve it in the browser (SQL editor)

Org Chart: All Reports Under Each Manager

Difficulty: Hard · Topics: recursive-cte, hierarchy, graphs · Asked at: Microsoft, Workday, Google, SAP

Problem

Using employees(id, name, manager_id), return for every employee: name, depth (CEO = 0), path of names from the CEO (separated by >) and total_reports: the number of people directly or indirectly reporting to them. Order by path.

Schema and sample data

CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, manager_id INTEGER);
INSERT INTO employees VALUES
(1,'Ada',NULL),(2,'Ben',1),(3,'Cy',1),(4,'Di',2),(5,'Ed',2),(6,'Flo',4),(7,'Gus',3);

Expected output

namedepthpathtotal_reports
Ada0Ada6
Ben1Ada > Ben3
Di2Ada > Ben > Di1
Flo3Ada > Ben > Di > Flo0
Ed2Ada > Ben > Ed0
Cy1Ada > Cy1
Gus2Ada > Cy > Gus0

Hints

Hint 1

Recursive CTE #1 walks top-down to build depth and path.

Hint 2

Recursive CTE #2 (or the same one) enumerates every (ancestor, descendant) pair; count descendants per ancestor.

Solution

WITH RECURSIVE tree(id, name, depth, path) AS (
  SELECT id, name, 0, name FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.id, e.name, t.depth + 1, t.path || ' > ' || e.name
  FROM employees e JOIN tree t ON e.manager_id = t.id
), pairs(ancestor, descendant) AS (
  SELECT manager_id, id FROM employees WHERE manager_id IS NOT NULL
  UNION ALL
  SELECT p.ancestor, e.id FROM pairs p JOIN employees e ON e.manager_id = p.descendant
)
SELECT t.name, t.depth, t.path,
       (SELECT COUNT(*) FROM pairs p WHERE p.ancestor = t.id) AS total_reports
FROM tree t
ORDER BY t.path;

Explanation

Follow-up questions

Spark doesn't support recursive CTEs (before 4.x). Alternatives?

Iterative self-joins in PySpark until no new rows (fine for shallow hierarchies), GraphFrames for graph algorithms, or flatten the hierarchy in the source/ETL into a closure table.