将connect-by与递归with进行比较时,我注意到使用循环检测时结果集的差异。结果连接对我来说更直观,所以我想知道Oracle的实现是否包含错误,或者这是否是标准ANSI和预期行为。因此,我的问题是,如果您可以使用其他数据库(如MysqL,DB2,sql Server等)检查递归查询。如果这些数据库当然支持recursive with子句。
以下是它在Oracle 11.2.0.1.0上的工作原理
sql> select * 2 from t 3 / ID PARENT_ID ---------- ---------- 1 2 2 1 2 rows selected.
使用CONNECT BY语法的查询:
sql> select id 2,parent_id 3,connect_by_iscycle 4 from t 5 connect by nocycle parent_id = prior id 6 start with id = 1 7 / ID PARENT_ID CONNECT_BY_ISCYCLE ---------- ---------- ------------------ 1 2 0 2 1 1 2 rows selected.
这看起来很直观。但是,使用新的ANSI语法,它会再返回一行:
sql> with tr (id,parent_id) as 2 ( select id 3,parent_id 4 from t 5 where id = 1 6 union all 7 select t.id 8,t.parent_id 9 from t 10 join tr on t.parent_id = tr.id 11 ) cycle id set is_cycle to '1' default '0' 12 select id 13,parent_id 14,is_cycle 15 from tr 16 / ID PARENT_ID I ---------- ---------- - 1 2 0 2 1 0 1 2 1 3 rows selected.
这是您可以用来检查的脚本:
create table t ( id number,parent_id number ); insert into t values (1,2); insert into t values (2,1); commit; with tr (id,parent_id) as ( select id,parent_id from t where id = 1 union all select t.id,t.parent_id from t join tr on t.parent_id = tr.id ) cycle id set is_cycle to '1' default '0' select id,parent_id,is_cycle from tr;
解决方法
CONNECT_BY_ISCYCLE
的文档:
The
CONNECT_BY_ISCYCLE
pseudocolumn returns1
if the current row has a child which is also its ancestor
而在CYCLE
:
A row is considered to form a cycle if one of its ancestor rows has the same values for the cycle columns.
在您的示例中,第2行确实有一个子节点,它也是它的祖先,但它的id尚未返回。
换句话说,CONNECT_BY_ISCYCLE检查子项(尚未返回),而CYCLE检查当前行(已返回)。
CONNECT BY是基于行的,而递归CTE是基于集合的。
在递归CTE中没有“孩子”的概念。它是一个基于集合的操作,可以完全从树中产生结果。一般来说,锚点部分和递归部分甚至可以使用不同的表格。
由于递归CTE通常用于构建层次结构树,因此Oracle决定添加循环检查。但由于递归CTE的基于集合的方式运行,通常无法判断下一步是否会产生一个周期。
要执行“下一步”,整个“当前”集需要可用,但要生成当前集的每一行(包括循环列),我们只需要获得“下一步”操作的结果。单行(例如CONNECT BY)不是问题,但是整个集合存在问题。
还没有研究过Oracle 11,但是sql Server通过隐藏它们后面的CONNECT BY来实现递归CTE,这需要放置许多限制(所有限制都有效地禁止所有基于集合的操作)。
另一方面,Postgresql的实现是真正基于集合的。
如前所述,MysqL根本没有实现CTE(它也没有实现HASH JOIN或MERGE JOIN,只有嵌套循环,因此不要太惊讶)。
具有讽刺意味的是,我今天收到了一封关于这个主题的信,我将在我的博客中介绍。
更新: