如何使用SQL Server 2012对分层定义数据执行ROLLUP / SUBTOTAL?

时间:2014-03-26 04:41:20

标签: sql sql-server

我必须在这样定义的某些分层数据上获得“ROLLUP”或“SUBTOTALS”:

ZoneId ParentZoneId Name       Qty  
1      NULL         Zone 1     1    
2      1            Zone 1.2   2    
4      2            Zone 1.2.1 4    
5      2            Zone 1.2.2 5    
3      1            Zone 1.3   3    
6      NULL         Zone 2     6   
7      6            Zone 2.1   7    
8      6            Zone 2.2   8    

按区域查找小计。

为了实现这一点,我计算了一个“解决”每个区域层次结构并使用以下查询的“StructureId”:

select
    z.ZoneId,
    z.ParentZoneId,
    z.Name,
    z.StructureId,
    z.Qty,
    sum(subt.Qty) SubTotal
from 
    dbo.Zone as z join dbo.Zone as subt on
        subt.StructureId like z.StructureId + '%'
group by
    z.ZoneId,
    z.ParentZoneId,
    z.Name,
    z.StructureId,
    z.Qty
order by
    Name;

所以我实际上得到了正确的结果:

ZoneId ParentZoneId Name       Qty  StructureId  SubTotal
1      NULL         Zone 1     1    1.           15
2      1            Zone 1.2   2    1.2.         11
4      2            Zone 1.2.1 4    1.2.4.        4
5      2            Zone 1.2.2 5    1.2.          5
3      1            Zone 1.3   3    1.3.          3
6      NULL         Zone 2     6    6.           21
7      6            Zone 2.1   7    6.7.          7
8      6            Zone 2.2   8    6.8.          8

但是我需要使用一个过程来计算StructureId,所以我想知道,是否可以使用SQL Server 2012中的一些ROLLUP,CUBE或其他SELECT选项来解决这个问题?

提前致谢。

1 个答案:

答案 0 :(得分:2)

我知道这是一个古老的,但我偶然发现它,并找到了一些时间来回答(并非独立于我喜欢Common Table Expressions)。所以这里是代码:

with CTE (ZoneId, ParentZoneId, ChildId, SumQty) 
as (
  select z.ZoneId, z.ParentZoneId, null as childid, coalesce(z.Qty,0) as SumQty
  from Zone z

  union all

  select z.ZoneId, z.ParentZoneId, v.ZoneId as childid, coalesce(v.SumQty,0) as SumQty
  from Zone z inner join CTE v on z.ZoneId = v.ParentZoneId
)
select z.*, v.SumQty
from (select ZoneId, sum(SumQty) as SumQty from CTE group by ZoneId) v
inner join Zone z on v.ZoneId=z.ZoneId

有必要预先熟悉CTE(例如,WRT递归查询请参阅relevant MSDN page)。 CTE表达式为其自己的数量选择每个记录一次(所谓的“锚定成员定义”,UNION ALL的顶部),并为其每个子项选择一次(该子项的总数,即所谓的“递归成员定义” “,UNION ALL的底部。)

在尝试理解代码时,值得将主选择更改为select * from CTE order by 1以查看幕后发生的情况。 (注意,ChildId仅用于帮助此“调试”...另请注意,coalesce函数用于防止NULL Qty值传播 - 可能是也可能不是所需的行为;它在这里无动于衷,但在大多数情况下我发现这就是你想要的。)

select子句然后将直接或通过子项属于同一ZoneId的数量相加并加入其余属性。