考虑以下简单的有向无环图:
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两次:
parent_id child_id
1 2
3 4
2 3
3 4 // 2nd appearance!
如何防止查询进入已经描述过的子图中进行递归?如果在我的“递归成员”部分的查询中,我可以引用到迄今为止由递归CTE检索到的所有数据(并提供一个断言,指示排除已访问节点的递归成员),那么我就可以实现这一点。然而,我认为我只能访问由递归成员的最后一次迭代返回的数据。
当有很多这样的重复时,这将不会很好地扩展。有没有一种方法可以防止这种不必要的额外递归?
请注意,我可以在语句的最后一行使用“select distinct”来实现所需的结果,但我认为这似乎是在所有(重复的)递归完成之后应用的,因此我认为这不是理想的解决方案。
编辑-hainstech建议通过添加谓词来排除在起始集中明确存在的路径来停止递归,即仅递归
where foo.child_id not in (1,3)
。这仅适用于上面的情况,因为所有重复的部分都始于节点的锚定集。它不能解决一般情况,其中可能不存在这样的情况。例如,考虑向上述集合添加边缘1->4和4->5。即使使用建议的谓词,边缘4->5也将被捕获两次。:(