Voici une solution utilisant un CTE récursif. J'ai utilisé lvl
comme en-tête de colonne depuis level
est un mot réservé dans Oracle. Vous verrez également d'autres différences de terminologie. J'utilise "parent" pour le niveau immédiatement supérieur et "ancêtre" pour>=0 étapes (pour répondre à votre exigence d'afficher un nœud comme son propre ancêtre). J'ai utilisé un ORDER BY
clause pour que la sortie corresponde à la vôtre ; vous pouvez ou non avoir besoin des lignes commandées.
Votre question m'a incité à relire, plus en détail, les requêtes hiérarchiques, pour voir si cela peut être fait avec elles au lieu de CTE récursifs. En fait, je sais déjà que vous pouvez, en utilisant CONNECT_BY_PATH
, mais en utilisant une substr
là-dessus, récupérer le niveau supérieur dans un chemin hiérarchique n'est pas du tout satisfaisant, il doit y avoir un meilleur moyen. (Si c'était la seule façon de le faire avec des requêtes hiérarchiques, j'opterais certainement pour la voie CTE récursive si elle était disponible). J'ajouterai la solution de requête hiérarchique ici, si je peux en trouver une bonne.
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
Ajouté :Solution de requête hiérarchique
OK - trouvé. Veuillez tester les deux solutions pour voir laquelle fonctionne le mieux ; à partir de tests sur une configuration différente, le CTE récursif était un peu plus rapide que la requête hiérarchique, mais cela peut dépendre de la situation spécifique. AUSSI :le CTE récursif ne fonctionne que dans Oracle 11.2 et versions ultérieures ; la solution hiérarchique fonctionne avec les anciennes versions.
J'ai ajouté un peu plus de données de test pour correspondre à celles d'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