【发布时间】:2010-10-24 04:35:29
【问题描述】:
考虑以下简单的 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 被选中两次:
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 将被捕获两次,即使使用建议的谓词。 :(
【问题讨论】:
标签: sql sql-server recursion graph common-table-expression