Obter todos os subcaminhos em uma consulta hierárquica no Oracle

votos
0

Eu tenho uma tabela que contém uma lista de departamentos de vendas da seguinte forma:

+-------+---------------+-----------+
|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       |
+-------+---------------+-----------+

Eu preciso de uma consulta que retorna todos os subcaminhos possíveis. Assim, para as três primeiras linhas deve ser a seguinte:

5500 5510
5500 5511
5510 5511

por isso para cada possível subpath ele retornaria a primeira e última departamento do caminho. É bastante fácil de obter o caminho, fazendo isso:

    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

mas como posso obter todos os subcaminhos possíveis?

Publicado 13/01/2020 em 23:56
fonte usuário
Em outras línguas...                            


2 respostas

votos
0

Eu entendo que você deseja gerar uma mesa de encerramento, que contém todos os caminhos possíveis na hierarquia.

Aqui está uma solução que usa uma consulta recursiva padrão para conseguir isso. Eu também adicionei uma coluna que armazena a profundidade da relação, uma vez que esta informação é frequentemente útil em tabelas de fechamento.

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

Esta demo no DB Fiddle com os seus dados de amostra produz 30 linhas, cujos primeiros 10 são:

ANCESTOR | NÓ | 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
Respondeu 14/01/2020 em 00:39
fonte usuário

votos
1

Use CONNECT_BY_ROOTpara encontrar o início do caminho.

Configuração da 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;

consulta :

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;

saída :

ANCESTOR | DEPT_ID | CAMINHO                
-------: | ------: | : -------------------
    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 aqui

Respondeu 14/01/2020 em 00:50
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more