Oracle SQLは、独自のCONNECT BY構文を使用して、v2以降の階層クエリを実行できます。最新の11gリリース2では、再帰的サブクエリファクタリング(再帰的with句とも呼ばれます)が追加されました。これはANSI規格であり、私が正しく理解していれば、これは他のRDBMSベンダーによっても実装されています。
connect-byとrecursivewithを比較すると、循環検出を使用した場合の結果セットに違いがあることに気付きました。結果による接続は私にとってより直感的であるため、Oracleの実装にバグが含まれているのか、それともこれが標準のANSIであり、予想される動作であるのか疑問に思います。したがって、私の質問は、MySQL、DB2、SQLServerなどの他のデータベースを使用してクエリで再帰をチェックできるかどうかです。もちろん、これらのデータベースが再帰的なwith句をサポートしている場合。
Oracle11.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構文を使用すると、もう1行が返されます。
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;