Sql 递归查询中的循环检测
我的PostgreSQL数据库中有一个有向图,节点和循环之间可以有多条路径:Sql 递归查询中的循环检测,sql,postgresql,common-table-expression,Sql,Postgresql,Common Table Expression,我的PostgreSQL数据库中有一个有向图,节点和循环之间可以有多条路径: create table "edges" ("from" int, "to" int); insert into "edges" values (0, 1), (1, 2), (2, 3), (3, 4), (1, 3); insert into "edges" values (10, 11), (11, 12), (12, 11); 我想找出一个节点和连接到它的每个节点之间的最小边数: with recursive
create table "edges" ("from" int, "to" int);
insert into "edges" values (0, 1), (1, 2), (2, 3), (3, 4), (1, 3);
insert into "edges" values (10, 11), (11, 12), (12, 11);
我想找出一个节点和连接到它的每个节点之间的最小边数:
with recursive "nodes" ("node", "depth") as (
select 0, 0
union
select "to", "depth" + 1
from "edges", "nodes"
where "from" = "node"
) select * from "nodes";
返回所有路径的深度:
node 0 1 2 3 3 4 4
depth 0 1 2 2 3 3 4
0 -> 1 -> 2 -> 3 -> 4
0 -> 1 ------> 3 -> 4
我需要最低限度的,但是
在递归查询的递归项中不允许使用聚合函数
但在结果上使用聚合函数仍然有效:
with recursive "nodes" ("node", "depth") as (
select 0, 0
union all
select "to", "depth" + 1
from "edges", "nodes"
where "from" = "node"
) select * from (select "node", min("depth")
from "nodes" group by "node") as n;
回报如期
node 0 1 2 3 4
depth 0 1 2 2 3
但是,运行到循环中会导致无限循环,并且查询“节点”的递归引用不能出现在子查询中,因此我无法检查节点是否已被访问:
with recursive "nodes" ("node", "depth") as (
select 10, 0
union
select "to", "depth" + 1
from "edges", "nodes"
where "from" = "node"
and "to" not in (select "node" from "nodes")
) select * from "nodes";
我在这里寻找的结果是
node 10 11 12
depth 0 1 2
有没有一种方法可以通过递归查询/公共表表达式实现这一点
另一种方法是创建一个临时表,迭代地添加行,直到用完为止;i、 呼吸优先的搜索
相关:检查节点是否已包含在路径中并避免循环,但仍然无法避免执行不必要的工作,检查比已知最短路径长的路径,因为其行为仍类似于深度优先搜索您可以基于 此查询将返回您期望的数据
node 10 11 12
depth 0 1 2
with recursive "nodes" ("node", "depth", "path", "cycle") as (
select 10, 0, ARRAY[10], false
union all
select "to", "depth" + 1, path || "to", "to" = ANY(path)
from "edges", "nodes"
where "from" = "node" and not "cycle"
) select * from (select "node", min("depth"), "path", "cycle"
from "nodes" group by "node", "path", "cycle") as n
where not "cycle";