Sql 对树数据进行分组、聚合和求和的最佳方法是什么?

Sql 对树数据进行分组、聚合和求和的最佳方法是什么?,sql,sql-server,sql-server-2005,tsql,hierarchical,Sql,Sql Server,Sql Server 2005,Tsql,Hierarchical,给定一个自引用表 Item ------------- Id (pk) ParentId (fk) 具有关联值的相关表 ItemValue ------------- ItemId (fk) Amount 和一些样本数据 Item ItemValues Id ParentId ItemId Amount -------------------- ---------------------- 1

给定一个自引用表

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
我需要一个存储过程来获取
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并在那里执行递归。

“假设您的层次结构不太深入”不会,但如果这样做会有什么问题?在SQL Server上,递归深度默认限制为100。您可以使用MAXRECURSION查询提示指定高达32767的值,但我假设它不会随着超过某个阈值的体积线性扩展。不过,对于您的情况来说,这似乎不是一个问题,因为您将一次指定一位家长。只要索引正确,递归深度合理(小于100?),性能就不会有问题。可以使用CTE进行无限递归。设置MAXRECURSION=0。它在BOL.sqlserver2005中这样说,我也将重新标记