Aqui está uma solução usando um CTE recursivo. Eu usei
lvl
como cabeçalho de coluna desde level
é uma palavra reservada no Oracle. Você também verá outras diferenças na terminologia. Eu uso "pai" para o nível imediatamente mais alto e "ancestral" para>=0 etapas (para acomodar sua exigência de mostrar um nó como seu próprio ancestral). Eu usei um ORDER BY
cláusula para fazer com que a saída corresponda à sua; você pode ou não precisar das linhas ordenadas. Sua pergunta me estimulou a ler novamente, com mais detalhes, sobre consultas hierárquicas, para ver se isso pode ser feito com elas ao invés de CTEs recursivas. Na verdade, eu já sei que você pode, usando
CONNECT_BY_PATH
, mas usando um substr
em que apenas para recuperar o nível superior em um caminho hierárquico não é satisfatório, deve haver uma maneira melhor. (Se essa fosse a única maneira de fazer isso com consultas hierárquicas, eu definitivamente seguiria a rota CTE recursiva se estivesse disponível). Vou adicionar a solução de consulta hierárquica aqui, se eu encontrar uma boa. with h ( node, parent ) as (
select 1 , null from dual union all
select 2 , 1 from dual union all
select 3 , 2 from dual
),
r ( node , ancestor, steps ) as (
select node , node , 0
from h
union all
select r.node, h.parent, steps + 1
from h join r
on h.node = r.ancestor
)
select node, ancestor,
1+ (max(steps) over (partition by node)) as lvl, steps
from r
where ancestor is not null
order by lvl, steps desc;
NODE ANCESTOR LVL STEPS
---------- ---------- ---------- ----------
1 1 1 0
2 1 2 1
2 2 2 0
3 1 3 2
3 2 3 1
3 3 3 0
Adicionado :Solução de consulta hierárquica
OK - encontrei. Por favor, teste ambas as soluções para ver qual tem melhor desempenho; a partir de testes em uma configuração diferente, a CTE recursiva foi um pouco mais rápida que a consulta hierárquica, mas isso pode depender da situação específica. TAMBÉM:o CTE recursivo funciona apenas no Oracle 11.2 e superior; a solução hierárquica funciona com versões mais antigas.
Eu adicionei um pouco mais de dados de teste para corresponder aos de Anatoliy.
with h ( node, parent ) as (
select 1 , null from dual union all
select 2 , 1 from dual union all
select 3 , 2 from dual union all
select 4 , 2 from dual union all
select 5 , 4 from dual
)
select node,
connect_by_root node as ancestor,
max(level) over (partition by node) as lvl,
level - 1 as steps
from h
connect by parent = prior node
order by node, ancestor;
NODE ANCESTOR LVL STEPS
---------- ---------- ---------- ----------
1 1 1 0
2 1 2 1
2 2 2 0
3 1 3 2
3 2 3 1
3 3 3 0
4 1 3 2
4 2 3 1
4 4 3 0
5 1 4 3
5 2 4 2
5 4 4 1
5 5 4 0