我必须在这样定义的某些分层数据上获得“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选项来解决这个问题?
提前致谢。
答案 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
的数量相加并加入其余属性。