具有共享成员的 Oracle 层次结构(双 parent 成员)

Oracle Hierarchy with shared members (double parent members)

我正在处理分层数据,其中有些键具有双倍或三倍 parents。

我必须写一个分层查询来表示层次结构,但是这个双键或三键 parent 必须单独出现在树中,显示它们的孩子只能在三个中找到的第一个键中出现。

 WITH HER(CHILD, PARENT) AS (
     SELECT 'A' AS CHILD, null  AS PARENT FROM DUAL UNION
     SELECT 'B' AS CHILD, 'A'   AS PARENT FROM DUAL UNION
     SELECT 'C' AS CHILD, 'A'   AS PARENT FROM DUAL UNION
     SELECT 'D' AS CHILD, 'C'   AS PARENT FROM DUAL UNION
     SELECT 'E' AS CHILD, 'D'   AS PARENT FROM DUAL UNION
     SELECT 'F' AS CHILD, null  AS PARENT FROM DUAL UNION
     SELECT 'G' AS CHILD, 'F'   AS PARENT FROM DUAL UNION
     SELECT 'C' AS CHILD, 'G'   AS PARENT FROM DUAL UNION  --<<--- shared
     SELECT 'H' AS CHILD,  null AS PARENT FROM DUAL UNION
     SELECT 'B' AS CHILD,  'H'  AS PARENT FROM DUAL UNION  --<<--- shared
     SELECT 'X' AS CHILD,  null AS PARENT FROM DUAL UNION
     SELECT 'Y' AS CHILD,  'X'  AS PARENT FROM DUAL UNION
     SELECT 'Z' AS CHILD,  'Y'  AS PARENT FROM DUAL UNION
     SELECT 'C' AS CHILD,  'Z'  AS PARENT FROM DUAL       --<<--- shared  
    )
     SELECT 
         LPAD(' ', 7*(LEVEL-1),' ')||CHILD||' - '||PARENT
     FROM HER
     START WITH PARENT IS NULL
     CONNECT BY PRIOR CHILD = PARENT 

;

这个查询的结果是这样的,但这并不是我想要得到的:

----------
A - 
       B - A
       C - A
              D - C
                     E - D
F - 
       G - F
              C - G
                     *D - C*
                            *E - D*
H - 
       B - H
X - 
       Y - X
              Z - Y
                     C - Z
                            *D - C*
                                   *E - D*

行 D-C 和 E-D 应该只显示在 "C" 键的第一次出现中。所以我标有“*”的应该不会出现

我知道我可以创建一个辅助查询,在其中我发现这个 double-parent 键,然后根据这个排除行。 但我想知道是否有最短的方法来做到这一点,使用层次结构本身......是否有办法知道一个键已经有另一个 parent。 (因为这是在视图中进行的,所以我需要在查询中执行此操作,而不是 PL/SQL。)

提前致谢。

我承认我通常是 sql 服务器,所以这是您的想法,但它可能需要一些调整和语法帮助。但是如何添加一个 ROW_NUMBER() 在 Child 级别分区并在您的 connect by 子句中添加第二个条件以限制递归。也许是这样的?

 WITH HER(CHILD, PARENT) AS (
     SELECT 'A' AS CHILD, null  AS PARENT FROM DUAL UNION
     SELECT 'B' AS CHILD, 'A'   AS PARENT FROM DUAL UNION
     SELECT 'C' AS CHILD, 'A'   AS PARENT FROM DUAL UNION
     SELECT 'D' AS CHILD, 'C'   AS PARENT FROM DUAL UNION
     SELECT 'E' AS CHILD, 'D'   AS PARENT FROM DUAL UNION
     SELECT 'F' AS CHILD, null  AS PARENT FROM DUAL UNION
     SELECT 'G' AS CHILD, 'F'   AS PARENT FROM DUAL UNION
     SELECT 'C' AS CHILD, 'G'   AS PARENT FROM DUAL UNION  --<<--- shared
     SELECT 'H' AS CHILD,  null AS PARENT FROM DUAL UNION
     SELECT 'B' AS CHILD,  'H'  AS PARENT FROM DUAL UNION  --<<--- shared
     SELECT 'X' AS CHILD,  null AS PARENT FROM DUAL UNION
     SELECT 'Y' AS CHILD,  'X'  AS PARENT FROM DUAL UNION
     SELECT 'Z' AS CHILD,  'Y'  AS PARENT FROM DUAL UNION
     SELECT 'C' AS CHILD,  'Z'  AS PARENT FROM DUAL       --<<--- shared  
    )

    , HERChildRowNum(CHILD, PARENT, ChildRowNum) AS (

       SELECT
          CHILD,
          PARENT,
          ROW_NUMBER() OVER (PARTITION BY CHILD ORDER BY (SELECT 0)) as ChildRowNum
       FROM
          HER
    )


     SELECT 
         LPAD(' ', 7*(LEVEL-1),' ')||CHILD||' - '||PARENT
     FROM HERChildRowNum
     START WITH PARENT IS NULL
     CONNECT BY PRIOR CHILD = PARENT AND (PRIOR ChildRowNum = ChildRowNum OR ChildRowNum>1)