SQL Server 汇总数据之计算总计数据
虽然Reportin Service能够轻松地计算总计和小计,而无须查询做额外的工作。但实
践表明,向应用程序提供总计,让其在窗体或网页底端显示它可能很有用。
接下来的三个聚合命令将可以提供很好的解决方案。
一、Rollup 与Cube
两者基本语法一致:
group by ....
with rollup | cube
聚合函数Rollup 和Cube在一个独立的行中计算出小计和总计,并在分组依据列中包
含空值,以指出对应的值为总计。Rollup生成分组依据列的小计和总计行,而Cube扩展
了这种功能,为每个分组依据列生成总计和小计行,有一个名为grouping()的函数,它在行为总计或小计时返回真(1),否则返回0。
如:
--查出工资,并根据部门进行分组,得出总计小计
select
case grouping(C.bmname)
when 0 then C.bmname
when 1 then '工资总计'
end as 部门名称
,sum(A.basic_gz+A.jiaban_gz+A.jiangjin) 部门工资 from gongzi A
inner join yuangong B on A.ygid=B.id
inner join bumen C on B.bmID=c.id
group by C.bmname
with Rollup
--如果group by有多列,则还会返回小计,不只是总计
结果:
部门名称 部门工资
管理部 702
技术部 5469
客户部 1878
销售部 2200
工资总计 10249
分组依据多列:
--查出工资,并根据部门进行分组,得出总计小计
select
case grouping(C.bmname)
when 0 then C.bmname
when 1 then '工资总计'
end as 部门名称
,sum(A.basic_gz+A.jiaban_gz+A.jiangjin) 部门工资 from gongzi A
inner join yuangong B on A.ygid=B.id
inner join bumen C on B.bmID=c.id
group by C.ID,C.bmname
with Rollup
--如果group by有多列,则还会返回小计,不只是总计
结果:
部门名称 部门工资
技术部 5469
工资总计 5469
管理部 702
工资总计 702
销售部 2200
工资总计 2200
客户部 1878
工资总计 1878
工资总计 10249
注:rollup放在group by 子句的后面,命令SQL Server生成一个总计行
如果使用的是cube,那么总计行与小计行的显示全部放在最后,且支持像rollup分组小计
,直接跟着分组后。这是对rollup的一个扩展。
二、compute 与compute by
Compute子句,不是创建聚合查询,而是在常规查询后面添加一个聚合查询。该查询
返回一个包含明细数据行的常规结果集,然后加上几行,其中包含该结果集的汇总信息。
compute 聚合函数(列名1),聚合函数(列名2) [by] 分组依据列
注:加上了by就有了分组小计,而不只是总计,且不可与group by 共同使用,这是为了
向后兼容才提供的,一般使用Rollup 与cube
三、创建交叉表查询
虽然聚合查询能够根据多个列进行分组,但结果分行排列的,不太方便快速查看数据
。交叉表查询将分组依据列(或一维)逆时针旋转90°,将其变成结果集中的列。
如:
Category South East West Total
X 100 0 20 100
Y 200 300 50 550
Z 0 0 100 100
这是一个根据种类来进行分组,其中每个小组计算的是这种类别各个地区对应的销售量,
以及这种类别总销售量。
局限性:分行排列的Group by查询可以有多个聚合函数,而交叉查询只能显示一种
度量方式(只能计算一种聚合函数)。
注:术语:交叉表查询,描述的是结果集的外观,而不是创建交叉表的方法。
有多种方法生成交叉表。
四、固定列交叉表查询
创建包含已知的固定列交叉表查询的方法有三种。
1、使用相关子查询。2、使用Case表达式
3、使用透视
1、使用相关子查询
性能差,对于每个分组依据列的每个度量方式实例执行一次子查询。
如:
Select R.Category,
(select Sum(Amount) from RawData where Region='South' and
Category=R.category ) as 'South',
(select Sum(Amount) from RawData where Region='North' and
Category=R.category ) as 'North',
(select Sum(Amount) from RawData where Region='East' and
Category=R.category ) as 'East',
(select Sum(Amount) from RawData where Region='West' and
Category=R.category ) as 'West',
Sum(Amount) as Total
from RawData R
group by Category
2、使用Case表达式
使用Case表达式来筛选将被汇总的数据,而不是在相关子查询中筛选数据,这样
查询引擎可以将整个交叉表查询作为单个基于数据集的操作进行处理。
注:最适用方便的创建交叉表查询的方法
如:
Select R.Category,
sum(Case Region when 'South' then Amount else 0 end) as South,
sum(Case Region when 'North' then Amount else 0 end) as North,
sum(Case Region when 'East' then Amount else 0 end) as East,
sum(Case Region when 'West' then Amount else 0 end) as West,
Sum(Amount) as Total
from RawData R
group by Category
order by Category
这个查询没有使用任何Where子句来筛选RawData表中的数据,Group by 子句根据类
别对数据集进行划分。然后执行聚合函数为每个类别创建一个结果行。
注:该查询使用了一个技巧,在Sum()中使用了一个Case表达式,这样每列只考虑
一个地区的值。
3、使用透视
这种方法它在From子句执行聚合函数。并创建一个交叉表,将其作为数据源,
如将Pivot看作一个用作数据源的表值函数,则它接受两个参数。
第一个参数是用于对交叉表的值进行计算的聚合函数,第一个参数列出了被透视
的列。
基本语法:
(数据源)
PIVOT
(聚合函数)
条件
五、动态交叉表查询
使用PIVOT和游标实现。