3

给定一个自引用表

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,但想知道是否有更好/更快的方法。

4

3 回答 3

7

假设您的层次结构不会太深,这样的递归 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) 上的索引。

于 2009-10-23T01:35:54.993 回答
0

你能把你的数据存储在嵌套集合模型中吗(这里有一个 MySQL参考,但这些想法是跨数据库通用的)?如果是这样,那么查找您正在寻找的值的操作将相当简单。

于 2009-10-23T01:47:48.743 回答
0

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

于 2009-10-23T03:46:31.780 回答