首页 > 解决方案 > 带有递归 SQL 查询的无限循环

问题描述

我似乎无法在此查询中找到无限循环背后的原因,也找不到如何纠正它。

这是上下文:我有一个名为 mergesWith 的表,其描述如下: mergesWith:有关邻近海域的信息。请注意,在这种关系中,对于每一对相邻的海洋 (A,B),只给出一个元组——因此,这种关系不是对称的。sea1:一片海 sea2:一片海。

我想通过导航了解从地中海可到达的每一个海洋。我选择了使用 "with" 的递归查询:

With 
   acces(p,d) as (
       select sea1 as p, sea2 as d
       from MERGESWITH
       UNION ALL
       select a.p, case when mw.sea1=a.d 
                       then mw.sea2 
                       else mw.sea1 
                   end as d
       from acces a, MERGESWITH mw
       where a.d=mw.sea1 or a.d=mw.sea2)
select d
from acces
where p= 'Mediterranean Sea';

我认为原因要么是要么case when不够a.d=mw.sea1 or a.d=mw.sea2严格,但我似乎无法确定原因。

我收到此错误消息: 32044. 00000 -“执行递归 WITH 查询时检测到循环” *原因:递归 WITH 子句查询产生了一个循环,并被停止以避免无限循环。*行动:重写递归 WITH 查询以停止递归或使用 CYCLE 子句。

标签: sqloraclerecursionwith-statementhierarchical-query

解决方案


循环是由查询的结构引起的,而不是由数据中的循环引起的。你问骑自行车的原因。这应该很明显:在第一次迭代中,一行输出具有d = 'Aegean Sea'. 在第二次迭代中,您会发现一行带有d = 'Mediterranean Sea',对吗?你现在能看到这将如何导致循环吗?

递归查询有一个cycle专门用于此类问题的子句。出于某种原因,即使是许多很好地学习了递归with子句并一直使用它的用户,似乎也没有意识到该cycle子句(以及不相关但同样有用的search子句 - 用于对输出进行排序)。

在您的代码中,您需要进行两项更改。添加cycle子句,并且仅在非循环行的外部查询过滤器中添加。在cycle子句中,您可以决定如何调用“循环”列,以及赋予它什么值。为了使其看起来尽可能类似于connect by查询,我喜欢调用新列IS_CYCLE并为其赋予值 0(表示无循环)和 1(表示循环)。在下面的外部查询中,添加is_cycleselect列表以查看它添加到递归查询中的内容。

注意cycle子句的位置:它紧跟递归with子句之后(特别是在递归因式子查询末尾的右括号之后)。

with 
   acces(p,d) as (
       select sea1 as p, sea2 as d
       from   MERGESWITH
       UNION ALL
       select  a.p, case when mw.sea1=a.d 
                         then mw.sea2 
                         else mw.sea1 
                    end  as d
       from   acces a, MERGESWITH mw
       where  a.d=mw.sea1 or a.d=mw.sea2)
       cycle  d set is_cycle to 1 default 0           -- add this line
select d
from   acces
where  p= 'Mediterranean Sea'
  and  is_cycle = 0                                   -- and this line
;

推荐阅读