Запрос иерархии управления

Попытка создать SQL-запрос, который принимает идентификатор сотрудника, имя сотрудника, уровень сотрудника, идентификатор руководителя и имя руководителя и возвращает все те же данные для каждой записи со структурой org для данного сотрудника, а не из генерального директора.

В идеале я хочу добиться:

employee_id, name, employee_level, supervisor_id, supervisor_name, L1_supervisor_id, L1_supervisor_name, L2_supervisor_id, L2_supervisor_name...

Я могу получить иерархию управления от генерального директора, используя следующее:

SELECT
lev01.employee_id id_01, lev01.name name_01, lev01.emp_type class_01,
lev02.employee_id id_02, lev02.name name_02, lev02.emp_type class_02,
lev03.employee_id id_03, lev03.name name_03, lev03.emp_type class_03,
lev04.employee_id id_04, lev04.name name_04, lev04.emp_type class_04,
lev05.employee_id id_05, lev05.name name_05, lev05.emp_type class_05,
lev06.employee_id id_06, lev06.name name_06, lev06.emp_type class_06,
lev07.employee_id id_07, lev07.name name_07, lev07.emp_type class_07,
lev08.employee_id id_08, lev08.name name_08, lev08.emp_type class_08,
lev09.employee_id id_09, lev09.name name_09, lev09.emp_type class_09,
lev10.employee_id id_10, lev10.name name_10, lev10.emp_type class_10,
lev11.employee_id id_11, lev11.name name_11, lev11.emp_type class_11,
lev12.employee_id id_12, lev12.name name_12, lev12.emp_type class_12,
lev13.employee_id id_13, lev13.name name_13, lev13.emp_type class_13,
lev14.employee_id id_14, lev14.name name_14, lev14.emp_type class_14,
lev15.employee_id id_15, lev15.name name_15, lev15.emp_type class_15,
lev16.employee_id id_16, lev16.name name_16, lev16.emp_type class_16,
lev17.employee_id id_17, lev17.name name_17, lev17.emp_type class_17,
lev18.employee_id id_18, lev18.name name_18, lev18.emp_type class_18
FROM emp_lst lev01
LEFT OUTER JOIN emp_lst lev02 ON lev01.employee_id = lev02.supervisor_id
LEFT OUTER JOIN emp_lst lev03 ON lev02.employee_id = lev03.supervisor_id
LEFT OUTER JOIN emp_lst lev04 ON lev03.employee_id = lev04.supervisor_id
LEFT OUTER JOIN emp_lst lev05 ON lev04.employee_id = lev05.supervisor_id
LEFT OUTER JOIN emp_lst lev06 ON lev05.employee_id = lev06.supervisor_id
LEFT OUTER JOIN emp_lst lev07 ON lev06.employee_id = lev07.supervisor_id
LEFT OUTER JOIN emp_lst lev08 ON lev07.employee_id = lev08.supervisor_id
LEFT OUTER JOIN emp_lst lev09 ON lev08.employee_id = lev09.supervisor_id
LEFT OUTER JOIN emp_lst lev10 ON lev09.employee_id = lev10.supervisor_id
LEFT OUTER JOIN emp_lst lev11 ON lev10.employee_id = lev11.supervisor_id
LEFT OUTER JOIN emp_lst lev12 ON lev11.employee_id = lev12.supervisor_id
LEFT OUTER JOIN emp_lst lev13 ON lev12.employee_id = lev13.supervisor_id
LEFT OUTER JOIN emp_lst lev14 ON lev13.employee_id = lev14.supervisor_id
LEFT OUTER JOIN emp_lst lev15 ON lev14.employee_id = lev15.supervisor_id
LEFT OUTER JOIN emp_lst lev16 ON lev15.employee_id = lev16.supervisor_id
LEFT OUTER JOIN emp_lst lev17 ON lev16.employee_id = lev17.supervisor_id
LEFT OUTER JOIN emp_lst lev18 ON lev17.employee_id = lev18.supervisor_id
WHERE lev01.supervisor_id IS NULL;

Это не хватает в двух областях:

  1. Запрос немного сложен для чтения и обслуживания. Я уверен, что есть способ оптимизировать / сократить его, но до сих пор я не смог найти подходящую альтернативу.

  2. Без исходных записей становится ручным процессом сопоставления этих записей с исходной таблицей.

Подойдет любой вкус SQL, но я использую SQLite здесь.

1 ответ

Вам нужны рекурсивные запросы!

WITH RECURSIVE org_chart(employee_id, name, emp_type) AS (
  SELECT employee_id, name, emp_type
  FROM emp_lst
  WHERE supervisor_id IS NULL

  UNION ALL

  SELECT employee_id, name, emp_type
  FROM emp_lst e JOIN org_chart o ON e.supervisor_id = o.employee_id 
)
SELECT * FROM org_chart;

Узнайте больше по ссылке, которую я предоставил.

SQLite поддерживает рекурсивные запросы начиная с версии 3.8.3 (2014-02-03).

Почти все другие марки баз данных SQL также поддерживают синтаксис рекурсивных запросов. См. https://www.percona.com/blog/2014/02/11/wither-recursive-queries/

MySQL является последним, кто добавил поддержку, и это будет в следующей версии 8.0.

Другие вопросы по тегам