SQL:找到最长的路径

时间:2017-03-13 16:20:44

标签: sql postgresql graph

我对图论非常陌生,并且很难解决这个问题。给定一个简单的表(单向),如何使用select语句找到定义的起点和终点的最长路径?

似乎需要一些递归语句,但我无法理解它。如果有人可以提供帮助,那就太棒了。

我正在使用Postgresql。

+ -------- + ------ + -------- +
| fromnode | tonode | distance |
+ -------- + ------ + -------- +
| 1        | 2      | 1306     |
| 1        | 6      | 2661     |
| 2        | 3      | 919      |
| 2        | 4      | 629      |
| 3        | 4      | 435      |
| 3        | 5      | 1225     |
| 3        | 7      | 1983     |
| 5        | 6      | 1483     |
| 5        | 7      | 1258     |
+ -------- + ------ + -------- +

1 个答案:

答案 0 :(得分:2)

您可以使用此递归CTE,例如:

with recursive params as (
  select 1 fromnode,
         7 tonode
),
paths as (
    select ARRAY[fromnode] pathnodes,
           fromnode lastnode,
           0 sumdistance
    from   params
  union all
    select     pathnodes || e.tonode,
               e.tonode,
               sumdistance + e.distance
    from       paths
    join       edges e on e.fromnode = lastnode
    cross join params p
    where      e.fromnode <> p.tonode
    and        e.tonode <> all(pathnodes)
)
select   pathnodes, sumdistance
from     paths, params
where    lastnode = tonode
order by sumdistance desc
limit    1

(此处和那里可能需要 ,具体取决于列的类型。)

http://rextester.com/VRFHK43986

然而,这将始终计算每个可能的路径(从params.fromnode开始;没有圆圈)&amp;之后会选择最长的。

修改:上面的解决方案假定图表是定向的。如果它是无向的,您可以对其进行修改,以便使用从tonodefromnode的边缘:

with recursive params as (
  select 7 fromnode,
         1 tonode
),
paths as (
    select ARRAY[fromnode] pathnodes,
           fromnode lastnode,
           0 sumdistance
    from   params
  union all
    select     pathnodes || e.nodeb,
               e.nodeb,
               sumdistance + e.distance
    from       paths
    cross join lateral (select fromnode nodea,
                               tonode   nodeb,
                               distance
                        from   edges
                        where  fromnode = lastnode
                        union
                        select tonode   nodea,
                               fromnode nodeb,
                               distance
                        from   edges
                        where  tonode = lastnode) e
    cross join params p
    where      e.nodea <> p.tonode
    and        e.nodeb <> all(pathnodes)
)
select   pathnodes, sumdistance
from     paths, params
where    lastnode = tonode
order by sumdistance desc
limit    1;

但是,(LEAST(fromnode, tonode), GREATEST(fromnode, tonode))可能需要一个唯一索引,以避免重复,row1.fromnode = row2.tonode and row1.tonode = row2.fromnode。 (查询不处理这种类型的重复,并且在这种情况下将使用2个单独的路径进行计算。)

http://rextester.com/XEGAX60117