当前位置: 首页 > 面试题库 >

在递归查询中检测周期

林弘壮
2023-03-14
问题内容

我的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 "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
  select "to", min("depth") + 1
  from "edges", "nodes"
  where "from" = "node"
  group by "to"
) select * from "nodes";

但是,对结果使用聚合函数可以:

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

有没有办法用递归查询/通用表表达式来做到这一点?

另一种方法是创建一个临时表,迭代添加行,直到用完为止。即呼吸优先搜索。


问题答案:

您可以根据文档在查询中添加周期检测

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";

该查询将返回您期望的数据



 类似资料:
  • 问题内容: 我有一组按层次结构组织的数据,应该可以增长到任意大小。我需要检索整个树,但是我无法弄清楚如何仅使用SQL来完成。我当前的解决方案是创建一个临时表,并使用递归函数依次查询树的分支,然后将结果存储在临时表中,随后我再次对其进行查询以产生所需的结果。 我的问题是,从本质上讲,我正在执行的联接正确吗?构造一个中间表,然后查询结果。似乎应该有一种使用联接的方法,但是MySQL文档仅涵盖检索有限深

  • 问题内容: JPA 2是否具有运行递归查询的任何机制? 这是我的情况:我有一个实体E,其中包含一个整数字段x。它还可能具有通过@OneToMany映射的E类型的子代。我想做的是通过主键找到一个E,并获取其x的值以及所有后代的x值。有没有办法在单个查询中执行此操作? 我正在使用Hibernate 3.5.3,但我不希望在Hibernate API上没有任何明确的依赖关系。 编辑:根据这一项目,Hib

  • 问题内容: 我对PLSQL的更高级主题还是陌生的,因此希望有人可以帮助我。 问题: 我有一个表,其中包含管理员和用户之间发送的消息。该表在同一表的message_id字段中具有带FK的message_parent:如果填充了该字段,则意味着该消息是作为对先前消息的答复而发送的。我需要选择属于同一对话的所有消息并显示它们。可以通过单个查询完成此操作,还是需要一个过程来处理这种逻辑?据我了解,它必须是

  • 问题内容: 我在数据库中存储了一组依赖项。我正在寻找直接或间接依赖于当前对象的所有对象。由于对象可以依赖零个或多个其他对象,因此完全可以合理地认为对象1被对象9两次依赖(9依赖于4和5,这两个都依赖于1)。我想获取不依赖复制的所有依赖于当前对象的对象的列表。 如果存在循环,这将变得更加复杂。没有循环,一个人可以使用DISTINCT,尽管多次经过长链仅在末尾剔除它们仍然是一个问题。但是,对于循环,重

  • 问题内容: 我有下表: 我想让所有行都回溯,直到不再有parentID为止。因此, “ .... WHERE id = 5” 会给我: 问题答案: 您正在使用邻接表模型来组织层次结构数据。这种递归操作很困难的事实实际上是该模型的一个主要缺点。 一些DBMS(例如SQL Server 2005,Postgres 8.4和Oracle 11g)支持使用带有关键字的常用表表达式进行递归查询。 对于MyS

  • 问题内容: 基于现有表,我使用了CTE递归查询来得出以下数据。但是无法进一步应用它。 数据如下 我想从上述数据递归形成完整路径。意味着递归将给出以下输出。 谢谢 问题答案: 以下是CTE的示例: