给出一个自引用表
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,但我想知道是否有更好/更快的方法。
答案 0 :(得分:6)
这样的递归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)的索引。
答案 1 :(得分:0)
你能否像嵌套集模型那样存储你的数据(这里是一个MySQL reference,但这些想法在数据库中是通用的)?如果是这样,那么找到您正在寻找的值的操作将非常简单。
答案 2 :(得分:0)
这是否必须在数据库中处理?我建议将必要的数据放入BLL并在那里执行递归。