Oracle /互惠路径

时间:2018-02-13 11:21:15

标签: oracle path

我有一个查询,可以获得两点之间的路径:

with nodes (node) as (
    select 'A' from dual union all
    select 'B' from dual union all
    select 'C' from dual union all
    select 'D' from dual
),
connected_nodes (node_1,node_2 ) as
(
    select 'A','B' from dual union all
    select 'B','C' from dual union all
    select 'B','D' from dual union all
    select 'A','C' from dual union all
    select 'A','D' from dual union all
    select 'D','C' from dual union all
    select 'C','D' from dual
)
select ltrim(sys_connect_by_path(node_1, '->'), '->') as path,
       level -1 as hops
from
    (
    select node as node_1, node_2
    from nodes
           left join connected_nodes
             on(node = node_1)
    )         
where node_1 = 'C'               
connect by nocycle prior node_2 = node_1
               and prior node_1 is not null
start with node_1 = 'A'         

它工作得很好所以如果我需要从A到C获得路径,它会给出:

PATH             HOPS
---------- ----------
A->B->C             2
A->B->D->C          3
A->C                1
A->D->C             2

我需要的是让路径互惠,这意味着从A到C的过程与从C到A的过程相同,但在上面的查询中并非如此,就像我请求路径一样从C到A,它不会返回数据。

您可以帮我调整查询以满足我的需求吗?

2 个答案:

答案 0 :(得分:1)

要获得相反的路径,你需要以另一种方式走树;我不认为你可以在一个分层查询中做到这一点,而不会引入一些奇怪的转移。

您可以将搜索方向联合起来:

with connected_nodes (node_1,node_2 ) as
(
    select 'A','B' from dual union all
    select 'B','C' from dual union all
    select 'B','D' from dual union all
    select 'A','C' from dual union all
    select 'A','D' from dual union all
    select 'D','C' from dual union all
    select 'C','D' from dual
)
select ltrim(sys_connect_by_path(node_1, '->'), '->') as path,
       level -1 as hops
from connected_nodes
where node_1 = 'C'               
connect by nocycle prior node_2 = node_1
               and prior node_1 is not null
start with node_1 = 'A'
union all
select ltrim(sys_connect_by_path(node_1, '->'), '->') as path,
       level -1 as hops
from connected_nodes
where node_1 = 'C'
connect by nocycle prior node_1 = node_2
               and prior node_2 is not null
start with node_1 = 'A'
/

对于您的初始条件仍会得到相同的结果:

PATH                                                     HOPS
-------------------------------------------------- ----------
A->B->C                                                     2
A->B->D->C                                                  3
A->C                                                        1
A->D->C                                                     2

但是所有引用AC的反转都会产生反向路径:

with connected_nodes (node_1,node_2 ) as
(
    select 'A','B' from dual union all
    select 'B','C' from dual union all
    select 'B','D' from dual union all
    select 'A','C' from dual union all
    select 'A','D' from dual union all
    select 'D','C' from dual union all
    select 'C','D' from dual
)
select ltrim(sys_connect_by_path(node_1, '->'), '->') as path,
       level -1 as hops
from connected_nodes
where node_1 = 'A'               
connect by nocycle prior node_2 = node_1
               and prior node_1 is not null
start with node_1 = 'C'
union all
select ltrim(sys_connect_by_path(node_1, '->'), '->') as path,
       level -1 as hops
from connected_nodes
where node_1 = 'A'
connect by nocycle prior node_1 = node_2
               and prior node_2 is not null
start with node_1 = 'C'
/

PATH                                                     HOPS
-------------------------------------------------- ----------
C->A                                                        1
C->B->A                                                     2
C->D->A                                                     2
C->D->B->A                                                  3

您不需要内联视图,或直接引用node表,至少需要您的示例数据。联合的第一个分支在一个方向上进行分层查询;第二个分支转向另一个方向,交换priornot null检查中的引用。一个分支总是没有行,另一个分支得到你想要的路径;开始/结束条件决定哪个分支得到哪个。

答案 1 :(得分:1)

如果您有双向图表,请使用UNION ALL在查询中同时包含node_1, node_2和反向node_2, node_1

with connected_nodes (node_1,node_2 ) as
(
    select 'A','B' from dual union all
    select 'B','C' from dual union all
    select 'B','D' from dual union all
    select 'A','C' from dual union all
    select 'A','D' from dual union all
    select 'D','C' from dual union all
    select 'C','D' from dual
)
select SUBSTR(sys_connect_by_path(node_2, '->'), 3) as path,
       level -1 as hops
from   ( SELECT node_1, node_2 FROM connected_nodes
         UNION ALL
         SELECT node_2, node_1 FROM connected_nodes
         UNION ALL
         SELECT null, 'C' FROM DUAL -- Fake connection to start vertex which
                                    -- prevents C being revisited with the
                                    -- NOCYCLE keyword.
       )
where node_2 = 'A'
start with node_1 IS null
connect by nocycle prior node_2 = node_1;

<强>输出

PATH        HOPS
----------- ----
C->A        1
C->B->A     2
C->B->D->A  3
C->D->A     2
C->D->B->A  3
C->D->A     2
C->D->B->A  3