AdvancedJOINs (INNER, LEFT, RIGHT, FULL)

Recursive self-join: full org chart hierarchy

The query

SQL
WITH RECURSIVE org_chart AS (
  -- Base: top-level employees (no manager)
  SELECT emp_id, first_name, last_name, manager_id, 1 AS level,
    ARRAY[emp_id] AS path
  FROM employees
  WHERE manager_id IS NULL

  UNION ALL

  -- Recursive: employees with managers
  SELECT e.emp_id, e.first_name, e.last_name, e.manager_id,
    oc.level + 1, oc.path || e.emp_id
  FROM employees e
  JOIN org_chart oc ON e.manager_id = oc.emp_id
  WHERE NOT e.emp_id = ANY(oc.path) -- prevent cycles
)
SELECT
  REPEAT('  ', level - 1) || first_name || ' ' || last_name AS org_tree,
  level AS hierarchy_level
FROM org_chart
ORDER BY path;
Tested against PostgreSQL 16

Note

Recursive CTE for tree traversal. Used for org charts, category trees, bill of materials.

Tables referenced