【问题标题】:PostgreSQL SQL or PL/pgSQL query for traversing a directed graph and returning all edges found用于遍历有向图并返回找到的所有边的 PostgreSQL SQL 或 PL/pgSQL 查询
【发布时间】:2011-03-27 07:58:12
【问题描述】:

我不是特别习惯于生成复杂的 SQL 查询,并且很难将我对过程语言和基于集合的操作的理解混合在 为网络遍历设计递归查询。我希望通过对有向图进行深度优先搜索来找到位于特定节点“上游”的一组边(每个节点可以有多个上游边),并且最好在 SQL 中实现这一点。

我想要做的伪代码如下所示:

interesting_pipes = Pipes[]

func find_all_pipes_upstream(node n)
 if is_inlet(nodename)
    return Nil
 else
   for p in upstream_pipes:
     if p in interesting_pipes:
       return Nil
   else
     interesting_pipes.append(p)
     find_all_pipes_upstream(upstream_node(p))

我已经用纯 SQL 编写了以下函数:

upstream_pipes(node_name varchar) RETURNS SETOF "Pipes"
upstream_node(pipe_name varchar) RETURNS "Node"
is_inlet(node_name) RETURNS boolean

但我正在努力弄清楚如何管理范围和返回类型 将上述伪代码转换为 PostgreSQL WITH RECURSIVE 查询或 PL/pgSQL 函数时。我见过的大多数WITH RECURSIVE 查询示例都是为遍历每个节点只有一个父节点的树而设计的。有没有人有任何提示/建议如何最好地解决这个问题?

干杯,

【问题讨论】:

    标签: sql postgresql recursion plpgsql


    【解决方案1】:

    见:

    http://www.postgresql.org/docs/8.4/static/queries-with.html

    如果链接关系包含循环,则此查询将循环。因为我们需要“深度”输出,所以仅将 UNION ALL 更改为 UNION 不会消除循环。相反,我们需要识别在遵循特定链接路径时是否再次到达同一行。我们在容易循环的查询中添加两列路径和循环:

    WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (
            SELECT g.id, g.link, g.data, 1,
              ARRAY[g.id],
              false
            FROM graph g
          UNION ALL
            SELECT g.id, g.link, g.data, sg.depth + 1,
              path || g.id,
              g.id = ANY(path)
            FROM graph g, search_graph sg
            WHERE g.id = sg.link AND NOT cycle
    )
    SELECT * FROM search_graph;
    

    【讨论】:

    • 谢谢,丹尼斯。在意识到我需要创建一个视图“graph(pipe_id,downstream_node_id,upstream_node_id)”后,我能够使用您引用的示例中的“WITH RECURSIVE”查询,这是作为非递归 WITH 子查询完成的确保每次调用主图遍历查询时只执行一次。现在,我的图形遍历所花费的时间是我使用 Python/ODBC 时的 1/200。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多