2009-10-23 57 views
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的孩子,爲他們,他們的孩子和他們的孩子一路下降EE。

例如,如果1傳遞中,樹是2, 3, 4, 5直接孩子2, 3輸出將

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

什麼樣的方法應該適用於使實現這種行爲?

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

+0

SQL Server 2005,我也會重寫 – Bob 2009-10-23 02:02:06

回答

5

遞歸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(金額)上的索引。

+0

」假設你的層次結構不會太深「,它不會,但是如果它出現問題會是什麼問題? – Bob 2009-10-23 02:00:46

+0

默認情況下,SQL Server上的遞歸深度限制爲100。您可以使用MAXRECURSION查詢提示指定高達32767,但我認爲它不會隨着音量高於某個閾值線性縮放。但是,對於您的情況,這似乎不是問題,因爲您一次只能指定一位家長。只要你有適當的索引和遞歸深度是合理的(低於100?),性能不應該成爲問題。 – 2009-10-23 02:24:38

+0

太棒了,謝謝! – Bob 2009-10-23 02:27:48

0

您可以將數據存儲爲嵌套集模型(這裏是MySQL reference,但這些想法在數據庫中是通用的)?如果是這樣的話,找到你正在尋找的值的操作將非常簡單。

+0

不幸的是結構現在確定。 – Bob 2009-10-23 01:52:21

0

這是否必須在數據庫中處理?我會建議將必要的數據帶入BLL並在那裏執行遞歸。 「

相關問題