Oracle CTE寻找祖父母和儿童的孩子

时间:2013-10-16 10:02:27

标签: oracle common-table-expression

我是甲骨文新手...相对来说......

我正在尝试在我继承的Oracle表上使用CTE。它比我希望的要复杂一点,因为“顶层”没有明确定义。

create table testConnectBy ( parent number, child number );

insert into testConnectBy values ( 1,  1);
insert into testConnectBy values ( 1, 11);
insert into testConnectBy values ( 1, 12);
insert into testConnectBy values ( 2,  2);
insert into testConnectBy values ( 2, 13);
insert into testConnectBy values (11, 11);
insert into testConnectBy values (11, 20);
insert into testConnectBy values (11, 21);
insert into testConnectBy values (12, 12);
insert into testConnectBy values (12, 22);
insert into testConnectBy values (12, 23);
insert into testConnectBy values (12, 24);
insert into testConnectBy values (13, 13);
insert into testConnectBy values (13, 30);
insert into testConnectBy values (13, 31);
insert into testConnectBy values (30, 30);
insert into testConnectBy values (30, 40);

此查询获取所有必需的行但是有一些重复(这是问题的第一部分,我想,最好如何删除)。由于存在循环问题(父==孩子),我不得不包括nocycle。

select *
  from testConnectBy 
  start with parent = '1'
  connect by nocycle prior child = parent;

下一个问题是,我希望能够输入11例如,并找出所有的父母和孩子。我不知道哪些父母或孩子与11有关。只是我需要用11来找到它们。

此查询仅返回11的子项。有没有办法返回两个“方向”?

select *
  from testConnectBy 
  start with parent = '11'
  connect by nocycle prior child = parent;

提前致谢。

1 个答案:

答案 0 :(得分:1)

关于第一个问题,请使用以下内容。它没有任何可以在PATH中检查的副本

SELECT
            PARENT,
            CHILD,
            LEVEL,
            CONNECT_BY_ISLEAF AS ISLEAF,
            CONNECT_BY_ISCYCLE AS ISCYCLE,
            CONNECT_BY_ROOT PARENT
            || SYS_CONNECT_BY_PATH ( CHILD,
                                ' ~ ' )
                AS PATH
       FROM
            TESTCONNECTBY
       CONNECT BY
            NOCYCLE PARENT = PRIOR CHILD
       START WITH
            PARENT = '1';

这将返回

1    1    1    0    1    1 ~ 1
1    11    2    0    1    1 ~ 1 ~ 11
11    20    3    1    0    1 ~ 1 ~ 11 ~ 20
11    21    3    1    0    1 ~ 1 ~ 11 ~ 21
1    12    2    0    1    1 ~ 1 ~ 12
12    22    3    1    0    1 ~ 1 ~ 12 ~ 22
12    23    3    1    0    1 ~ 1 ~ 12 ~ 23
12    24    3    1    0    1 ~ 1 ~ 12 ~ 24
1    11    1    0    1    1 ~ 11
11    20    2    1    0    1 ~ 11 ~ 20
11    21    2    1    0    1 ~ 11 ~ 21
1    12    1    0    1    1 ~ 12
12    22    2    1    0    1 ~ 12 ~ 22
12    23    2    1    0    1 ~ 12 ~ 23
12    24    2    1    0    1 ~ 12 ~ 24

如果你想避免PARENT = CHILDREN,那么

SELECT
            PARENT,
            CHILD,
            LEVEL,
            CONNECT_BY_ISLEAF AS ISLEAF,
            CONNECT_BY_ISCYCLE AS ISCYCLE,
            CONNECT_BY_ROOT PARENT
            || SYS_CONNECT_BY_PATH ( CHILD,
                                ' ~ ' )
                AS PATH
       FROM
            (SELECT * FROM TESTCONNECTBY WHERE PARENT <> CHILD)
       CONNECT BY
            NOCYCLE PARENT = PRIOR CHILD
       START WITH
            PARENT = '1';

结果

1    11    1    0    0    1 ~ 11
11    20    2    1    0    1 ~ 11 ~ 20
11    21    2    1    0    1 ~ 11 ~ 21
1    12    1    0    0    1 ~ 12
12    22    2    1    0    1 ~ 12 ~ 22
12    23    2    1    0    1 ~ 12 ~ 23
12    24    2    1    0    1 ~ 12 ~ 24

对于第二个问题,您可以使用以下代码段

SELECT
      *
FROM
      (SELECT
            PARENT,
            CHILD,
            LEVEL,
            CONNECT_BY_ISLEAF AS ISLEAF,
            CONNECT_BY_ISCYCLE AS ISCYCLE,
            CONNECT_BY_ROOT PARENT
            || SYS_CONNECT_BY_PATH ( CHILD,
                                ' ~ ' )
                AS PATH
       FROM
            TESTCONNECTBY
       CONNECT BY
            NOCYCLE PARENT = PRIOR CHILD
       START WITH
            PARENT = '1')
WHERE
      PARENT = 11
      OR CHILD = 11;

此查询返回

1    11    2    0    1    1 ~ 1 ~ 11
11    20    3    1    0    1 ~ 1 ~ 11 ~ 20
11    21    3    1    0    1 ~ 1 ~ 11 ~ 21
1    11    1    0    1    1 ~ 11
11    20    2    1    0    1 ~ 11 ~ 20
11    21    2    1    0    1 ~ 11 ~ 21

因为父母11有一个孩子11.如果你想排除自己的孩子,那么

SELECT
      *
FROM
      (SELECT
            PARENT,
            CHILD,
            LEVEL,
            CONNECT_BY_ISLEAF AS ISLEAF,
            CONNECT_BY_ISCYCLE AS ISCYCLE,
            CONNECT_BY_ROOT PARENT
            || SYS_CONNECT_BY_PATH ( CHILD,
                                ' ~ ' )
                AS PATH
       FROM
            (SELECT * FROM TESTCONNECTBY WHERE PARENT <> CHILD)
       CONNECT BY
            NOCYCLE PARENT = PRIOR CHILD
       START WITH
            PARENT = '1')
WHERE
      PARENT = 11
      OR CHILD = 11;

将返回

1    11    1    0    0    1 ~ 11
11    20    2    1    0    1 ~ 11 ~ 20
11    21    2    1    0    1 ~ 11 ~ 21