Ho dati in una tabella Oracle organizzata come un grafico che può contenere cicli (vedere esempio).Query gerarchica Oracle su dati non gerarchici
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
Il mio obiettivo è quello di ottenere tutti i nodi che sono discendenti (figli, figli dei figli, etc.) di nodo X. Diciamo 2. Il mio risultato atteso è quindi: 3, 4, 5, 6, 8.
So che posso progettare una query come questa:
SELECT child, sys_connect_by_path(child,'/')
FROM T
START WITH parent = 2
CONNECT BY NOCYCLE PRIOR child = PARENT;
Il problema con una tale domanda è che si passerà attraverso tutti i possibili percorsi fino a quando non ciclano, e ce ne sono troppi nei miei dati reali. Il risultato è costituito da molti duplicati - Eccolo:
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
miei dati reale è molto più complessa. il costo dell'esecuzione di una tale query è così grande che il mio tablespace TEMP, che era autoextendable, ha raggiunto 10Gb (originariamente 500 Mb) e il mio database in realtà si è rotto a causa del disco pieno.
ho cercato di progettare la query come questo (ricorsiva con un clausola):
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
Il problema che ho incontrato è:
- con Oracle 10g, questo non è implementato (
ORA-32033: unsupported column aliasing
, e alcuni clienti utilizzano Oracle 9 o 10), - con Oracle 11g, ottengo
ORA-32041: UNION ALL operation in recursive WITH clause must have only two branches
. Se rimuovo la clausola MINUS riceverò i cicli (ORA-32044: cycle detected while executing recursive WITH query
).
In che modo interrogheresti i miei dati originali per ottenere quei nodi 3, 4, 5, 6, 8 in modo efficiente? Anche le soluzioni PL/SQL sono benvenute.
Grazie.
questo sembra buono, grazie. Questo è un caso per avere un tavolo temporaneo globale? – Benoit
Non vorrei che la tabella fosse globale. Immagina il casino che potrebbe accadere se due processi iniziassero a usarlo insieme? (È già aperto a comportamenti "insoliti" se la tabella di origine viene modificata a metà dell'esecuzione, ma è possibile proteggere l'intera operazione in una transazione, se necessario.) – MatBailie
@Dems: solo una nota su _global tabelle temporanee_ come hai affermato tu Non sei un esperto di Oracle. In Oracle le cose sono diverse: [Qual è la differenza tra una tabella temporanea vs una tabella temporanea globale in Oracle?] (Http://stackoverflow.com/q/417764) e [Creazione di una tabella temporanea] (http: // download. oracle.com/docs/cd/E11882_01/server.112/e17120/tables003.htm#ADMIN11633) – user272735