Aquí hay una solución usando un CTE recursivo. Usé lvl
como encabezado de columna desde level
es una palabra reservada en Oracle. También verá otras diferencias en la terminología. Uso "padre" para el nivel inmediatamente superior y "antepasado" para>=0 pasos (para adaptarse a su requisito de mostrar un nodo como su propio antepasado). Usé un ORDER BY
cláusula para hacer que la salida coincida con la suya; puede o no necesitar las filas ordenadas.
Su pregunta me animó a leer nuevamente, con más detalle, sobre consultas jerárquicas, para ver si esto se puede hacer con ellas en lugar de CTE recursivos. En realidad, ya sé que puedes, usando CONNECT_BY_PATH
, pero usando un substr
en eso, solo recuperar el nivel superior en una ruta jerárquica no es satisfactorio en absoluto, debe haber una mejor manera. (Si esa fuera la única forma de hacerlo con consultas jerárquicas, definitivamente elegiría la ruta CTE recursiva si estuviera disponible). Agregaré la solución de consulta jerárquica aquí, si puedo encontrar una buena.
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
Añadido :solución de consulta jerárquica
Bien, lo encontré. Pruebe ambas soluciones para ver cuál funciona mejor; a partir de pruebas en una configuración diferente, la CTE recursiva fue un poco más rápida que la consulta jerárquica, pero eso puede depender de la situación específica. TAMBIÉN:el CTE recursivo solo funciona en Oracle 11.2 y superior; la solución jerárquica funciona con versiones anteriores.
Agregué un poco más de datos de prueba para que coincidan con los 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