#postgresql #recursion #recursive-query
#postgresql #рекурсия #рекурсивный запрос
Вопрос:
Давайте представим иерархию сотрудников в следующей таблице:
CREATE TABLE employee(
id serial PRIMARY KEY,
first_name varchar NOT NULL,
manager_id integer,
FOREIGN KEY(manager_id) REFERENCES employee(id)
);
INSERT INTO employee(first_name, manager_id)
VALUES('Arden', null),
('Oliver', null),
('Luisa', null),
('Amelia', null),
('Olivia', null),
('Lily', 2),
('Ava', 2),
('Isabella', 2),
('Charlie', 2),
('Beatrice', 3),
('Stephanie', 3),
('Emily', 3),
('Mila', 3),
('Isla', 4),
('Ashley', 4),
('James', 7),
('Jack', 7),
('William', 8),
('Harry', 8),
('Robin', 8);
Для сотрудника, например, с id = 20, мы можем найти менеджера самого высокого уровня, используя запрос:
WITH RECURSIVE cte AS
(
SELECT
0 cnt, id, first_name, manager_id
FROM
employee
WHERE
id = 20
UNION ALL
SELECT
cnt 1, employee.id, employee.first_name, employee.manager_id
FROM
cte INNER JOIN employee ON cte.manager_id = employee.id
)SELECT * FROM cte WHERE cnt = (SELECT max(cnt) FROM cte);
Но мне нужно получить весь список сотрудников — highest_level_manager
как показано ниже:
employee | highest_level_manager
----------------------------------
Robin | Oliver
Harry | Oliver
William | Oliver
Jack | Oliver
James | Oliver
Ashley | Amelia
Isla | Amelia
Mila | Luisa
Emili | Luisa
Stephanie | Luisa
Beatrice | Luisa
Charlie | Oliver
Isabella | Oliver
Ava | Oliver
Lily | Oliver
Olivia | null
Amelia | null
Luisa | null
Oliver | null
Arden | null
Кто-нибудь знает, как это сделать?
Ответ №1:
Пройдитесь по дереву для всех сотрудников. Уменьшите рекурсию до ids
, добавьте имена в конечный запрос:
with recursive cte as
(
select
id, manager_id, 0 as level
from
employee
union all
select
c.id, e.manager_id, level 1
from cte c
join employee e on c.manager_id = e.id and e.manager_id is not null
)
select
e.first_name as employee,
m.first_name as highest_level_manager
from (
select distinct on(id) *
from cte
order by id desc, level desc
) c
join employee e on c.id = e.id
left join employee m on c.manager_id = m.id
Смотрите живую демонстрацию в Db<>fiddle .
Комментарии:
1. Это действительно красивое решение! Большое спасибо!