Получить все подпути в иерархическом запросе в Oracle - PullRequest
1 голос
/ 13 января 2020

У меня есть таблица, которая содержит список отделов продаж следующим образом:

+-------+---------------+-----------+
|DEPT_ID|DEPT_NAME      |DEPT_PARENT|
+-------+---------------+-----------+
|5500   |World          |           |
|5510   |Region 1       |5500       |
|5511   |Cell 1 Region 1|5510       |
|5512   |Cell 2 Region 1|5510       |
|5513   |Cell 3 Region 1|5510       |
|5514   |Cell 4 Region 1|5510       |
|5515   |Cell 5 Region 1|5510       |
|5520   |Region 2       |5500       |
|5521   |Cell 1 Region 2|5520       |
|5522   |Cell 2 Region 2|5520       |
|5530   |Region 3       |5500       |
|5531   |Cell 1 Region 3|5530       |
|5532   |Cell 2 Region 3|5530       |
|5540   |Region 4       |5500       |
|5533   |Cell 1 Region 4|5540       |
|5534   |Cell 2 Region 4|5533       |
|5590   |Region 5       |5500       |
|5591   |Cell 1 Region 5|5590       |
+-------+---------------+-----------+

Мне нужен запрос, который возвращает все возможные подпути. Таким образом, для первых трех строк это должно быть следующим образом:

5500 5510
5500 5511
5510 5511

, поэтому для каждого возможного подпути будет возвращаться первый и последний отдел пути. Получить путь довольно просто, выполнив это:

    SELECT d.*, LTRIM (SYS_CONNECT_BY_PATH (dept_id, '-'), '-') AS PATH
      FROM depts d
START WITH dept_parent IS NULL
CONNECT BY PRIOR dept_id = dept_parent

но как мне получить все возможные подпути?

Ответы [ 2 ]

1 голос
/ 14 января 2020

Используйте CONNECT_BY_ROOT, чтобы найти начало пути.

Oracle Настройка :

CREATE TABLE depts ( DEPT_ID, DEPT_NAME, DEPT_PARENT ) AS
SELECT 5500, 'World',           NULL FROM DUAL UNION ALL
SELECT 5510, 'Region 1',        5500 FROM DUAL UNION ALL
SELECT 5511, 'Cell 1 Region 1', 5510 FROM DUAL UNION ALL
SELECT 5512, 'Cell 2 Region 1', 5510 FROM DUAL UNION ALL
SELECT 5513, 'Cell 3 Region 1', 5510 FROM DUAL UNION ALL
SELECT 5514, 'Cell 4 Region 1', 5510 FROM DUAL UNION ALL
SELECT 5515, 'Cell 5 Region 1', 5510 FROM DUAL UNION ALL
SELECT 5520, 'Region 2',        5500 FROM DUAL UNION ALL
SELECT 5521, 'Cell 1 Region 2', 5520 FROM DUAL UNION ALL
SELECT 5522, 'Cell 2 Region 2', 5520 FROM DUAL UNION ALL
SELECT 5530, 'Region 3',        5500 FROM DUAL UNION ALL
SELECT 5531, 'Cell 1 Region 3', 5530 FROM DUAL UNION ALL
SELECT 5532, 'Cell 2 Region 3', 5530 FROM DUAL UNION ALL
SELECT 5540, 'Region 4',        5500 FROM DUAL UNION ALL
SELECT 5533, 'Cell 1 Region 4', 5540 FROM DUAL UNION ALL
SELECT 5534, 'Cell 2 Region 4', 5533 FROM DUAL UNION ALL
SELECT 5590, 'Region 5',        5500 FROM DUAL UNION ALL
SELECT 5591, 'Cell 1 Region 5', 5590 FROM DUAL;

Запрос :

SELECT CONNECT_BY_ROOT( dept_parent ) AS ancestor,
       dept_id,
       SYS_CONNECT_BY_PATH( dept_parent, '>' ) || '>' || dept_id AS path
FROM   depts
START WITH dept_parent IS NOT NULL
CONNECT BY PRIOR dept_id = dept_parent;

Выход :

ANCESTOR | DEPT_ID | PATH                
-------: | ------: | :-------------------
    5500 |    5510 | >5500>5510          
    5500 |    5511 | >5500>5510>5511     
    5500 |    5512 | >5500>5510>5512     
    5500 |    5513 | >5500>5510>5513     
    5500 |    5514 | >5500>5510>5514     
    5500 |    5515 | >5500>5510>5515     
    5500 |    5520 | >5500>5520          
    5500 |    5521 | >5500>5520>5521     
    5500 |    5522 | >5500>5520>5522     
    5500 |    5530 | >5500>5530          
    5500 |    5531 | >5500>5530>5531     
    5500 |    5532 | >5500>5530>5532     
    5500 |    5540 | >5500>5540          
    5500 |    5533 | >5500>5540>5533     
    5500 |    5534 | >5500>5540>5533>5534
    5500 |    5590 | >5500>5590          
    5500 |    5591 | >5500>5590>5591     
    5510 |    5511 | >5510>5511          
    5510 |    5512 | >5510>5512          
    5510 |    5513 | >5510>5513          
    5510 |    5514 | >5510>5514          
    5510 |    5515 | >5510>5515          
    5520 |    5521 | >5520>5521          
    5520 |    5522 | >5520>5522          
    5530 |    5531 | >5530>5531          
    5530 |    5532 | >5530>5532          
    5533 |    5534 | >5533>5534          
    5540 |    5533 | >5540>5533          
    5540 |    5534 | >5540>5533>5534     
    5590 |    5591 | >5590>5591          

db <> Fiddle здесь

0 голосов
/ 14 января 2020

Я понимаю, что вы хотите создать таблицу замыкания, которая содержит все возможные пути в иерархии.

Вот решение, которое использует стандартный рекурсивный запрос для достижения этой цели. Я также добавил столбец, в котором хранится глубина взаимосвязи, поскольку эта информация часто полезна в таблицах закрытия.

with cte(node_id, dept_id, dept_parent, lvl) as (
    select dept_id node_id, dept_id, dept_parent, 0 lvl from dept
    union all 
    select c.node_id, d.dept_id, d.dept_parent, c.lvl + 1
    from cte c
    inner join dept d on d.dept_id = c.dept_parent
)
select dept_id ancestor, node_id node, lvl 
from cte 
where lvl > 0
order by node, ancestor

Это демонстрация на DB Fiddle с ваш пример данных дает 30 строк, первые 10 из которых:

ANCESTOR | NODE | LVL
-------: | ---: | --:
    5500 | 5510 |   1
    5500 | 5511 |   2
    5510 | 5511 |   1
    5500 | 5512 |   2
    5510 | 5512 |   1
    5500 | 5513 |   2
    5510 | 5513 |   1
    5500 | 5514 |   2
    5510 | 5514 |   1
    5500 | 5515 |   2
...