问题描述
我对Oracle 11g表有无向图数据的递归查询。每行代表一条边。递归查询遍历从给定输入边开始的所有边。查询的想法是:
-输入边缘处于第0级
-对于n>0,如果边缘位于 (第n-1) 级,则边缘位于第n级。
查询:
该查询与其他输入配合良好,直到出现同一节点对之间的两个平行边为止。在这种情况下,在递归的第0级 (初始行) 上存在边1。我预计边缘2将被添加到递归的第一级结果,因为连接条件成立。相反,我得到 “ORA-32044: 循环检测时执行递归查询”。
我知道当新加入递归查询结果的行与某些现有行相同时,会报告此错误。我不明白的是为什么Oracle将具有相同节点id但不同边缘id的行视为重复。添加
子句为新行提供iscycle = 1,并添加
给出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。
谢谢。
-输入边缘处于第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子句中使用的列的值。
所以当你只有:
数据库确实认为这是一个循环,因为边缘2与边缘1 (它的祖先) 具有完全相同的a,B值。
通过添加edge_seen和multiset union废话,您所做的就是实现自己的循环子句!
您可以删除此内容并仅在ID上循环:
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 1X Y 0 1 2 X Y X Y 0
文章转载自ASKTOM,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




