次の単純な DAG を検討してください。
1->2->3->4
そして、これを説明するテーブル #bar (私は SQL Server 2005 を使用しています):
parent_id child_id
1 2
2 3
3 4
//... other edges, not connected to the subgraph above
ここで、最初と最後のエッジ、つまり 1->2 と 3->4 を選択する別の任意の基準があるとします。これらを使用して、グラフの残りの部分を見つけたいと思います。
次のように再帰的な CTE を記述できます ( MSDNの用語を使用しています)。
with foo(parent_id,child_id) as (
// anchor member that happens to select first and last edges:
select parent_id,child_id from #bar where parent_id in (1,3)
union all
// recursive member:
select #bar.* from #bar
join foo on #bar.parent_id = foo.child_id
)
select parent_id,child_id from foo
ただし、これによりエッジ 3->4 が 2 回選択されます。
parent_id child_id
1 2
3 4
2 3
3 4 // 2nd appearance!
クエリが既に記述されているサブグラフに再帰するのを防ぐにはどうすればよいですか? クエリの「再帰メンバー」部分で、これまでに再帰 CTE によって取得されたすべてのデータを参照できれば、これを実現できます(そして、既にアクセスしたノードを除く再帰メンバーを示す述語を提供できます)。ただし、再帰メンバーの最後の繰り返しで返されたデータにのみアクセスできると思います。
このような繰り返しが多い場合、これはうまくスケーリングしません。この不必要な追加の再帰を防ぐ方法はありますか?
ステートメントの最後の行で「個別選択」を使用して目的の結果を得ることができることに注意してください。
Edit -hainstech は、述語を追加して再帰を停止し、開始セットに明示的に含まれていた再帰パスを除外することを提案しています。つまり、 recurse onlywhere foo.child_id not in (1,3)
です。上記のケースでこれが機能するのは、単純だからです。すべての繰り返されるセクションは、ノードのアンカー セット内で始まります。そうでない可能性がある一般的なケースは解決しません。たとえば、エッジ 1->4 および 4->5 を上記のセットに追加することを検討してください。提案された述語を使用しても、エッジ 4->5 は 2 回キャプチャされます。:(