J'ai des données dans une table Oracle organisée sous la forme d'un graphique pouvant contenir des cycles (voir l'exemple).Requête hiérarchique Oracle sur des données non hiérarchiques
CREATE TABLE T (parent INTEGER, child INTEGER)
AS select 1 parent, 2 child from dual
union all select 1 parent, 8 child from dual
union all select 2 parent, 3 child from dual
union all select 2 parent, 4 child from dual
union all select 2 parent, 8 child from dual
union all select 3 parent, 4 child from dual
union all select 3 parent, 6 child from dual
union all select 4 parent, 5 child from dual
union all select 5 parent, 8 child from dual
union all select 6 parent, 5 child from dual
union all select 7 parent, 3 child from dual
union all select 7 parent, 5 child from dual
union all select 8 parent, 6 child from dual
Mon but est d'obtenir tous les nœuds qui sont des descendants (enfants, enfants d'enfants, etc.) du noeud X. Disons que 2. Mon résultat attendu est alors: 3, 4, 5, 6, 8.
Je sais que je peux concevoir une requête comme ceci:
SELECT child, sys_connect_by_path(child,'/')
FROM T
START WITH parent = 2
CONNECT BY NOCYCLE PRIOR child = PARENT;
Le problème avec une telle requête est qu'elle traversera tous les chemins possibles jusqu'à leur cycle, et il y en a trop dans mes données actuelles. Le résultat se compose de nombreux doublons - Ici, il est:
child | sys_connect_by_path (for information)
3 | /3
4 | /3/4
5 | /3/4/5
8 | /3/4/5/8
6 | /3/4/5/8/6
6 | /3/6
5 | /3/6/5
8 | /3/6/5/8
4 | /4
5 | /4/5
8 | /4/5/8
6 | /4/5/8/6
8 | /8
6 | /8/6
5 | /8/6/5
Mes données réelles est beaucoup plus complexe. le coût d'exécution d'une telle requête est si énorme que mon espace de table TEMP, qui était autoextendable, a atteint 10 Go (à l'origine 500 Mo) et ma base de données s'est cassée à cause du disque plein.
J'ai essayé de concevoir la requête comme celui-ci (récursif clause):
WITH descendants(node) AS
(SELECT 2 node FROM dual
UNION ALL
(
SELECT child
FROM T
INNER JOIN descendants D
ON T.parent = D.node
MINUS SELECT node FROM descendants
)
)
SELECT * FROM descendants
Le problème que je rencontre est:
- avec Oracle 10g, ce ne sont pas mis en œuvre (
ORA-32033: unsupported column aliasing
et certains clients utilisent Oracle 9 ou 10), - avec Oracle 11g, j'obtiens
ORA-32041: UNION ALL operation in recursive WITH clause must have only two branches
. Si je supprime la clause MINUS, j'obtiendrai des cycles (ORA-32044: cycle detected while executing recursive WITH query
).
Comment voulez-vous interroger mes données d'origine pour obtenir les nœuds 3, 4, 5, 6, 8 efficacement? Les solutions PL/SQL sont également les bienvenues.
Merci.
cela semble bon, merci. Est-ce un cas pour avoir une table temporaire globale? – Benoit
Je ne voudrais pas que la table soit globale. Imaginez le désordre qui pourrait arriver si deux processus commençaient à l'utiliser ensemble? (Il est déjà ouvert au comportement "inhabituel" si la table source est modifiée en mi-exécution, mais vous pouvez protéger le tout dans une transaction si vous en avez besoin.) – MatBailie
@Dems: Juste une note sur _global temporary tables_ comme vous l'avez dit n'êtes pas un expert Oracle. Dans Oracle, les choses sont différentes: [Quelle est la différence entre une table temporaire et une table temporaire globale dans Oracle?] (Http://stackoverflow.com/q/417764) et [Création d'une table temporaire] (http: // download. oracle.com/docs/cd/E11882_01/server.112/e17120/tables003.htm#ADMIN11633) – user272735