用于在每个层次结构级别聚合成本的SQL Server CTE

时间:2017-05-22 07:18:25

标签: sql-server common-table-expression hierarchical-data

我无法弄清楚如何编写一个CTE,它将成本从事务表汇总到一个自联接表,这样它就可以在层次结构的每个级别给出总成本。我汇总了一个非常简单的例子来说明问题。 以下是DDL和插入脚本,因此您可以重现这个问题,如果您非常友好地帮助我:

With cteAggregateCost
as  
(  
    select i.itemId, i.ParentId, t.Amount
    from Items i join Transactions t on i.ItemId = t.ItemId
union all
    select i.itemId, i.ParentId, t.Amount
    from Items i join cteAggregateCost c on i.ItemId = c.ParentId
    join Transactions t on i.ItemId = t.ItemId
)
select i.ParentId, i.ItemId, i.ItemName, sum(Amount) As AggregateCost
from Items i left join cteAggregateCost c on i.ItemId = c.ItemId
group by i.ParentId, i.ItemId, i.ItemName

以下是我一直在研究的CTE:

0

这是我得到的结果:

Bad Result

这是我希望得到的结果:

Hoped-for Result

正如您所看到的,除了前两行之外,所有行都在工作,这些行没有容器的成本,只有它们包含的项目。

非常感谢您提供的任何方向!

2 个答案:

答案 0 :(得分:2)

您可以像这样使用recursive CTE

;WITH temp AS 
(
   SELECT i.*, sum(isnull(t.Amount,0)) AS Amount 
   FROM @Items i
   LEFT JOIN @Transactions t ON t.ItemId = i.ItemId
   GROUP BY i.ItemId, i.ParentId, i.ItemName
)
,cteAggregateCost
as  
(  
   select i.ItemId, i.ItemId AS RootId, i.Amount  
   from temp i     
union all
   select i.ItemId, c.RootId, i.Amount 
   from cteAggregateCost c
   INNER JOIN temp i ON i.ParentId = c.ItemId
)
select i.*, ca.TotalAmount
from  @Items i 
CROSS APPLY 
(
   SELECT Sum(cac.Amount) AS TotalAmount
   FROM cteAggregateCost cac WHERE i.ItemId = cac.RootId
) ca
OPTION (MAXRECURSION 0)

演示链接:http://rextester.com/XMK96314

答案 1 :(得分:1)

谢谢你,TriV。你的答案很棒!但是,我确实找到了Xi Jin on the SQL Server forum发布的更简单的答案。这是他的解决方案:

    With cteAggregateCost
    as  
    (  
        select  i.itemId as rootid,i.itemid, i.ParentId
        from Items i 
        union all
        select rootid, i.itemId, i.ParentId
        from Items i join cteAggregateCost c on i.ParentId = c.ItemId
    )

    select a.parentid, a.ItemId , a.ItemName , sum(t.Amount) As AggregateCost
    from items a
    left join cteAggregateCost i on a.itemid = i.rootid 
    left join Transactions t on i.ItemId = t.ItemId
    group by a.parentid, a.ItemId, a.ItemName

当针对具有多层次关系的更大数据集进行测试时,两种解决方案都能提供与我所寻找的相同的正确结果。对我来说,习琳的回答更容易理解。我无法解决如何添加rootID技术,该技术保留了没有自己成本的项目的值,只有子项目的成本。