给出一个自引用表

Item 
-------------
Id (pk)
ParentId (fk)

使用相关值的相关表

ItemValue
-------------
ItemId (fk)
Amount

以及一些示例数据

Item                       ItemValues 
Id      ParentId           ItemId      Amount
--------------------       ----------------------
1       null               1           10
2       1                  3           40
3       1                  3           20
4       2                  4           10
5       2                  5           30
6       null
7       6
8       7

我需要一个sproc来获取 Item.Id 并为他们,他们的孩子和他们的孩子一直返回所有 ItemValue.Amounts 的总和的直接子项在树下。

例如,如果传入 1 ,树将是 2,3,4,5 ,直接子节点是 2,3 输出将是

 ItemId    Amount
 ------------------
 2         40     (values from ItemIds 4 & 5)
 3         60     (values from ItemId 3)

应该采用哪种方法来实现这种行为?

我正在考虑使用CTE,但我想知道是否有更好/更快的方法。

有帮助吗?

解决方案

这样的递归CTE会起作用,假设您的层次结构不太深:

declare @ParentId int;
set @ParentId = 1;

;with 
  Recurse as (
    select 
      a.Id as DirectChildId
    , a.Id
    from Item a 
    where ParentId = @ParentId
    union all
    select
      b.DirectChildId
    , a.Id
    from Item a 
    join Recurse b on b.Id = a.ParentId
    )
select
  a.DirectChildId, sum(b.Amount) as Amount
from Recurse a
left join ItemValues b on a.Id = b.ItemId
group by
  DirectChildId;

非CTE方法需要某种形式的迭代,基于游标或其他方式。因为它是一个存储过程,它是一种可能性,并且如果有大量数据可以递归,它可能会更好地扩展,只要你适当地切分数据。

如果聚集索引在Id上,请在ParentId上添加非聚集索引。作为覆盖索引,它将满足初始搜索和书签查找。然后,聚簇索引将帮助进行递归连接。

如果聚簇索引已经在ParentId上,则在Id上添加非聚集索引。它们在一起几乎与上述相同。对于ItemValues,如果实际表格宽于此值,您可能需要(ItemId)INCLUDE(Amount)的索引。

其他提示

你能否像嵌套集模型那样存储你的数据(这里是一个MySQL 参考但这些想法在数据库中是通用的)?如果是这样,那么找到您正在寻找的值的操作将非常简单。

这是否必须在数据库中处理?我建议将必要的数据放入BLL并在那里执行递归。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top