Tengo datos en una tabla de Oracle organizada como un gráfico que puede contener ciclos (ver ejemplo).Consulta jerárquica de Oracle en datos no jerárquicos
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
Mi objetivo es conseguir todos los nodos que son descendientes (hijos, hijos de los hijos, etc.) del nodo X. Digamos 2. Mi resultado esperado es entonces: 3, 4, 5, 6, 8.
Sé que puedo diseñar una consulta como esta:
SELECT child, sys_connect_by_path(child,'/')
FROM T
START WITH parent = 2
CONNECT BY NOCYCLE PRIOR child = PARENT;
El problema con este tipo de consulta es que va a ir a través de todos los caminos posibles hasta que completen el ciclo, y hay demasiados de ellos en mis datos reales. El resultado consiste en muchos duplicados - Aquí 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
Mis datos reales son mucho más complejos. el costo de ejecución de tal consulta es tan grande que mi tablespace TEMP, que era autoextendable, alcanzó 10Gb (originalmente 500 Mb) y mi base de datos se rompió debido a que el disco estaba lleno.
Me trataron de diseñar la consulta como la siguiente (recursiva con un cláusula):
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
El problema que encuentro es:
- con Oracle 10g, esto no se lleva a cabo (
ORA-32033: unsupported column aliasing
, y algunos clientes usan Oracle 9 o 10), - con Oracle 11g, obtengo
ORA-32041: UNION ALL operation in recursive WITH clause must have only two branches
. Si elimino la cláusula MINUS obtendré ciclos (ORA-32044: cycle detected while executing recursive WITH query
).
¿Cómo consultaría mis datos originales para obtener esos nodos 3, 4, 5, 6, 8 de manera eficiente? Las soluciones PL/SQL también son bienvenidas.
Gracias.
esto se ve bien, gracias. ¿Es este un caso para tener una tabla temporal global? – Benoit
No me gustaría que la mesa sea global. Imagine el desastre que podría pasar si dos procesos comenzaron a usarlo juntos. (Ya está abierto a un comportamiento "inusual" si la tabla de origen se modifica a mitad de la ejecución. Pero puede protegerlo todo en una transacción si es necesario). – MatBailie
@Dems: solo una nota sobre _global tables temporales_ como usted indicó No soy un experto en Oracle. En Oracle las cosas son diferentes: [¿Cuál es la diferencia entre una tabla temporal vs tabla temporal global en Oracle?] (Http://stackoverflow.com/q/417764) y [Creación de una tabla temporal] (http: // download. oracle.com/docs/cd/E11882_01/server.112/e17120/tables003.htm#ADMIN11633) – user272735