先前树的连接必须是对称的

时间:2011-09-15 13:28:08

标签: sql oracle

我通过先前的查询进行连接,在Oracle中构建我的树结构。这工作正常,但我有一个组件,需要一个对称的树来正确显示。

所以我的想法是如果节点位于低于最高级别的级别,则向树中注入更多节点。

e.g。如果我们有一棵树

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

我需要在运行时修改树,如下所示:

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

这将使我的树在运行时对称,以使组件工作。

是否有一个简单的Oracle查询或函数可以为此提供帮助,或者是否有一些可以帮助解决这个问题的SQL语句?

2 个答案:

答案 0 :(得分:1)

好的,经过大量的追踪和错误,我认为我找到了解决方案。

因此,如果您有一个测试表,则将其调用为xx_tree_test,其中包含3个字段:cd,sup_cd和name;我将测试数据添加到它,这个查询

      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;

会产生这样的结果:

enter image description here

要添加额外节点以将Leaf 1和Leaf 2置于同一级别,您需要此查询:

 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;

此查询不会产生此结果:

enter image description here

所以现在要做的就是将它打包成一个漂亮的视图来隐藏大量的SQL。

答案 1 :(得分:0)

我不认为它可以在SQL中完成,或者至少我想不出这样做的方法。在我看来,查询必须知道在执行之前需要多少级别。

也许,那么,你需要一个临时表,这样你就可以在你的逻辑中执行第二次传递,以便按照你想要的方式获得它。

您是否有可以显示这些数据的客户端组件?如果是这样,那么这可能是第二次通过的最简单的地方。