使用oracle connect by查找邻接列表模型中的所有节点

时间:2013-04-28 10:55:38

标签: sql oracle tree adjacency-list

鉴于以下模型:

create table child_parent (
  child number(3),
  parent number(3)
);

鉴于以下数据:

insert into child_parent values(2,1);
insert into child_parent values(3,1);
insert into child_parent values(4,2);
insert into child_parent values(5,2);
insert into child_parent values(6,3);

产生以下树:

        1
       / \
      2   3
     / \   \
    4   5   6

现在我可以找到5的父母:

SELECT parent FROM child_parent START WITH  child = 5 
              CONNECT BY NOCYCLE PRIOR parent = child;

但是如何从5开始获取所有节点(1,2,3,4,5,6)?

3 个答案:

答案 0 :(得分:2)

最后,我提出了类似这样的解决方案:

  SELECT child FROM child_parent START WITH parent =
   (
    SELECT DISTINCT parent FROM   
     (
      SELECT parent
      FROM child_parent
      WHERE CONNECT_BY_ISLEAF = 1
        START WITH child = 5
        CONNECT BY PRIOR parent = child
      UNION
      SELECT parent
      FROM child_parent
      WHERE parent = 5
     ) 
   )
   CONNECT BY NOCYCLE PRIOR child = parent
   UNION
   SELECT DISTINCT parent FROM   
   (
    SELECT parent
    FROM child_parent
    WHERE CONNECT_BY_ISLEAF = 1
      START WITH child = 5
      CONNECT BY PRIOR parent = child
    UNION
    SELECT parent
    FROM child_parent
    WHERE parent = 5
   );

它适用于所提供示例的所有节点。 但是,如果其中一个叶子具有第二个父节点,并且起始点位于此节点之上或位于不同分支中,则它不起作用。

但对我来说这已经足够了。

获取图中所有节点的解决方案可以是: 实现与上面查询相反的(从上到下),然后执行它们(从下到上,从上到下),反之亦然,直到找不到更多新节点。 这需要PL / SQL,我也不知道性能。

答案 1 :(得分:1)

使用5你不能遍历整棵树,即使你可以实现它也会非常棘手,因为它是一个叶元素。

尝试以下查询,它将遍历整个树,但您必须从root而不是leaf开始:

select * from (
SELECT child FROM child_parent START WITH  parent = 1 
              CONNECT BY NOCYCLE PRIOR child = parent
union
select 1 from dual)
order by child;

您可以将“1”替换为任何其他根元素,将打印该根目录下的所有元素,包括该根。

答案 2 :(得分:1)

Oracle的CONNECT BY语法用于遍历分层数据:它是单向的,因此不适合表示图形,这需要双向性。在一个查询中无法转到2 -> 1 -> 3,这是您从5开始获取所有节点所需要做的。


很久以前我回答了关于在层次结构中展平节点的问题(AKA传递闭包),即如果1->2->3为真,则“1> 3”也是如此。它链接到一篇论文,该论文演示了PL / SQL解决方案,以生成所有边并将它们存储在表中。在这种情况下可以使用类似的解决方案。但显然,如果图中的节点不经常使用,那么它才是实用的。所以也许它的用途有限。无论如何,find out more