2011-09-15 11 views
8

Tengo una conexión por consulta previa que construye la estructura de mi árbol en Oracle. Esto funciona bien, pero tengo un componente que requiere un árbol simétrico para mostrar correctamente.Conectar por árbol anterior debe ser simétrico

Mi idea es inyectar más nodos en el árbol si el nodo se encuentra en un nivel más bajo que el nivel más alto.

p. Ej. si tenemos un árbol

Root 
    +- Node 1 
    +- Leaf 1 (Level 3) 
    +- Node 2 
    +- Node 3 
     +- Leaf 2 (Level 4) 

que tenga que modificar el árbol en tiempo de ejecución a tener este aspecto:

Root 
    +- Node 1 
    +- Copy of Node 1 
     +- Leaf 1 (Level 4) 
    +- Node 2 
    +- Node 3 
     +- Leaf 2 (Level 4) 

Esto hará que mi árbol simétrica en tiempo de ejecución para el componente funcione.

¿Existe una consulta o función de Oracle fácil que pueda ayudar en esto, o alguna declaración de SQL que pueda ayudar en esto?

Respuesta

0

No creo que se pueda hacer en SQL, o al menos no se me ocurre una manera de hacerlo. Me parece que la consulta debería saber cuántos niveles esperar antes de que se ejecute.

Quizás, entonces, necesita una tabla temporal para que pueda realizar una segunda pasada en su lógica para obtenerla de la manera que desee.

¿Tiene un componente del lado del cliente que mostrará estos datos? Si es así, ese podría ser el lugar más simple para hacer este segundo pase.

1

Ok, después de mucho camino y error, creo que encontré la solución.

Entonces, si tiene una tabla de prueba, llámela xx_tree_test con 3 campos: cd, sup_cd y name; y añado los datos de prueba a la misma, esta consulta

 SELECT CD, 
      SUP_CD, 
      LEVEL AS LVL, 
      CASE WHEN CONNECT_BY_ISLEAF = 1 THEN 'L' ELSE NULL END AS LEAF, 
      LPAD (' ', 3 * LEVEL, ' .') || NAME AS NAME 
     FROM xx_tree_test 
     START WITH SUP_CD IS NULL 
     CONNECT BY PRIOR CD = SUP_CD; 

que le dará este resultado:

enter image description here

para agregar el nodo adicional para llevar la hoja 1 y 2 de la hoja al mismo nivel que necesita esta consulta:

SELECT CD, 
      SUP_CD, 
      LEVEL AS LVL, 
      CASE WHEN CONNECT_BY_ISLEAF = 1 THEN 'L' ELSE NULL END AS LEAF, 
      LPAD (' ', 3 * LEVEL, ' .') || NAME AS NAME   
     FROM (WITH FULL_TREE 
       AS ( SELECT CD, 
           SUP_CD, 
           LEVEL AS LVL, 
           CASE 
            WHEN CONNECT_BY_ISLEAF = 1 THEN 'L' 
            ELSE NULL 
           END 
            AS LEAF, 
           LPAD (' ', 3 * LEVEL, ' .') || NAME AS TREE_NAME, 
           NAME 
          FROM XX_TREE_TEST 
        START WITH SUP_CD IS NULL 
        CONNECT BY PRIOR CD = SUP_CD) 
      SELECT A.NAME, 
        A.CD, 
        A.SUP_CD, 
        A.LVL 
       FROM FULL_TREE A 
      WHERE NVL (LEAF, 'z') != 'L' 
      UNION ALL 
      SELECT CASE 
         WHEN TREE1.LVL + TREE2.ROW_NUM_GENERATED - 1 = 
           (SELECT MAX (LVL) FROM FULL_TREE) 
         THEN 
         TREE1.NAME 
         ELSE 
         'Copy of ' || TREE1.NAME 
        END 
         AS NAME, 
        CASE 
         WHEN TREE1.LVL + TREE2.ROW_NUM_GENERATED - 1 = 
           (SELECT MAX (LVL) FROM FULL_TREE) 
         THEN 
         CD 
         ELSE 
         CD || '`' || TO_CHAR (TREE2.ROW_NUM_GENERATED) 
        END 
         AS CD, 
        CASE 
         WHEN TREE2.ROW_NUM_GENERATED = 1 THEN SUP_CD 
         ELSE CD || '`' || TO_CHAR (TREE2.ROW_NUM_GENERATED - 1) 
        END 
         AS SUP_CD, 
        TREE1.LVL + TREE2.ROW_NUM_GENERATED AS LVL 
       FROM (SELECT FULL_TREE.NAME, 
           FULL_TREE.CD, 
           FULL_TREE.SUP_CD, 
           FULL_TREE.LVL 
         FROM FULL_TREE 
         WHERE LEAF = 'L') TREE1 
        JOIN 
         ( SELECT LEVEL AS ROW_NUM_GENERATED 
          FROM DUAL 
         CONNECT BY LEVEL <= (SELECT MAX (LVL) FROM FULL_TREE)) TREE2 
        ON (SELECT MAX (LVL) FROM FULL_TREE) + 1 >= 
         TREE2.ROW_NUM_GENERATED + TREE1.LVL 
      ORDER BY CD, LVL) 
START WITH SUP_CD IS NULL 
CONNECT BY PRIOR CD = SUP_CD; 

Sin esta consulta que le dará este resultado:

enter image description here

Todo lo que queda por hacer ahora es simplemente empaquetarlo en una bonita vista para ocultar las enormes cantidades de SQL.

Cuestiones relacionadas