【问题标题】:Find all nodes in an adjacency list model with oracle connect by使用 oracle 连接查找邻接列表模型中的所有节点
【发布时间】:2013-04-28 10:55:37
【问题描述】:

给定以下模型:

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)?

【问题讨论】:

    标签: sql oracle tree adjacency-list


    【解决方案1】:

    最后我想出了一个类似这样的解决方案:

      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,我也不知道性能。

    【讨论】:

      【解决方案2】:

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


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

      【讨论】:

        【解决方案3】:

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

        试试下面的查询,它会遍历整个树,但你必须从根而不是叶子开始:

        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”替换为任何其他根元素,该根下方的所有元素都将被打印,包括该根。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-23
          相关资源
          最近更新 更多