暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 在递归查询中检测到周期,似乎没有周期

ASKTOM 2020-09-16
589

问题描述

我对Oracle 11g表有无向图数据的递归查询。每行代表一条边。递归查询遍历从给定输入边开始的所有边。查询的想法是:

-输入边缘处于第0级
-对于n>0,如果边缘位于 (第n-1) 级,则边缘位于第n级。

查询:

with edges (id, a, b) as (
  select 1, 'X', 'Y' from dual union
  select 2, 'X', 'Y' from dual
), r (l, id, parent_a, parent_b, child_a, child_b, edge_seen) as (
  select 0, id, null, null, a, b, cast(collect(id) over () as sys.ku$_objnumset)
  from edges
  where id = 1 
  union all
  select r.l + 1, e.id, r.child_a, r.child_b, e.a, e.b
       , r.edge_seen multiset union distinct (cast(collect(e.id) over () as sys.ku$_objnumset))
  from r
  join edges e on (r.child_a in (e.a, e.b) or r.child_b in (e.a, e.b))
    and e.id not member of (select r.edge_seen from dual)
)
select * from r;


该查询与其他输入配合良好,直到出现同一节点对之间的两个平行边为止。在这种情况下,在递归的第0级 (初始行) 上存在边1。我预计边缘2将被添加到递归的第一级结果,因为连接条件成立。相反,我得到 “ORA-32044: 循环检测时执行递归查询”。

我知道当新加入递归查询结果的行与某些现有行相同时,会报告此错误。我不明白的是为什么Oracle将具有相同节点id但不同边缘id的行视为重复。添加

cycle child_a, child_b set iscycle to 1 default 0


子句为新行提供iscycle = 1,并添加

cycle id, child_a, child_b set iscycle to 1 default 0


给出iscycle = 0,这两者都是正确的。


Is it some known Oracle 11g bug and what's the best way to handle it?

我无法填写LiveSQL链接表单,因为LiveSQL仅支持Oracle 19,并且该问题仅在我无法从中迁移的Oracle 11g中可以重现。等效的dbfiddle是https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=43af3cfae920e31f9a2748c1c31b54ad

谢谢。

专家解答

从文档中:

A row is considered to form a cycle if one of its ancestor rows has the same values for the cycle columns.

即数据库不考虑整行,只考虑您在cycle子句中使用的列的值。

所以当你只有:

cycle child_a, child_b


数据库确实认为这是一个循环,因为边缘2与边缘1 (它的祖先) 具有完全相同的a,B值。

通过添加edge_seen和multiset union废话,您所做的就是实现自己的循环子句!

您可以删除此内容并仅在ID上循环:

with edges (id, a, b) as (
  select 1, 'X', 'Y' from dual union
  select 2, 'X', 'Y' from dual
), r (l, id, parent_a, parent_b, child_a, child_b) as (
  select 0, id, null, null, a, b
  from edges
  where id = 1 
  union all
  select r.l + 1, e.id, r.child_a, r.child_b, e.a, e.b
  from r
  join edges e on (r.child_a in (e.a, e.b) or r.child_b in (e.a, e.b))
) 
  cycle id set iscycle to 1 default 0
select * from r
where  iscycle = 0;

L    ID    PARENT_A    PARENT_B    CHILD_A    CHILD_B    ISCYCLE   
   0     1             X          Y          0          
   1     2 X           Y           X          Y          0    

文章转载自ASKTOM,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论