您的位置:首页 > 数据库

用SQL进行报表的小计和合计

2012-08-30 16:26 260 查看
最近在进行报表的测试,表中涉及到了添加行小计条件,当时在想用SQL怎么来实现行小计呢,于是上网搜素,还真有类似的文章,转来学习下又增长了知识。

但是有个疑问,一个表中针对一个数据列,用不同小计条件能否实现?希望大家可以给答复指导下,据说在Excel中是可以实现,比如说工资,又想按一年的每月进行小计,又想按人进行小计,有人说可以用group by实现,但是那样就相当于新增了一列,并不是按行来进行小计的。

用SQL实现统计报表中的“小计”和“合计”
  

 先来一段概念:

----------------------

 DECODE函数是ORACLE PL/SQL是功能强大的函数之一,目前还只有ORACLE公司的SQL提供了此函数,其他数据库厂商的SQL实现还没有此功能。DECODE有什么用途 呢? 先构造一个例子,假设我们想给智星职员加工资,其标准是:工资在8000元以下的将加20%;工资在8000元以上的加15%,通常的做法是,先选出记录 中的工资字段值? select salary into var-salary from employee,然后对变量var-salary用if-then-else或choose
case之类的流控制语句进行判断。 如果用DECODE函数,那么我们就可以把这些流控制语句省略,通过SQL语句就可以直接完成。如下:select decode(sign(salary - 8000),1,salary*1.15,-1,salary*1.2,salary from employee 是不是很简洁? DECODE的语法:DECODE(value,if1,then1,if2,then2,if3,then3,...,else),表示如果value 等于if1时,DECODE函数的结果返回then1,...,如果不等于任何一个if值,则返回else。初看一下,DECODE
只能做等于测试,但刚才也看到了,我们通过一些函数或计算替代value,是可以使DECODE函数具备大于、小于或等于功能。

--------------------------

在 开发统计报表的过程中,经常会碰到在查询到的数据集中,插入一些小计行和合计行。比如在烤烟系统中,几乎每个统计报表都需要加入“合计”行,还有不少涉及 到烟叶等级的统计报表需要加入各烟叶等级的小计行。我看到不少人(包括我自己)都是在程序中专门写一些方法来处理的,有的方法还很繁琐。最近在看SQL
Server2000的联机丛书中才发现,利用GROUPING聚合函数和ROLLUP运算符可以轻松实现统计中加入小计和合计功能。

1.     
GROUPPING和ROLLUP的基本知识

1.1.   
GROUPPING

是一个聚合函数,它产生一个附加的列,当用 CUBE 或 ROLLUP 运算符添加行时,附加的列输出值为1,当所添加的行不是由 CUBE 或 ROLLUP 产生时,附加列值为0。
语法:
GROUPING
(
column_name
)

参数: column_name是 GROUP BY 子句中用于检查 CUBE 或 ROLLUP 空值的列。
返回类型: int
备注: 分组用于区分由 CUBE 和 ROLLUP 返回的空值和标准的空值。作为CUBE 或 ROLLUP 操作结果返回的 NULL 是 NULL 的特殊应用。

1.2.   
ROLLUP

ROLLUP
运算符生成聚合汇总,
需要汇总信息时,此运算很有用。该运算符生成的结果集类似于
CUBE 运算符生成的结果集。但它们两者有一些区别,CUBE
生成的结果集显示了所选列中值的所有组合的聚合。而ROLLUP
生成的结果集显示了所选列中值的某一层次结构的聚合。
语法: ROLLUP
(
column_name1[
,column_name2。。。]
)

用法: 用在GROUP BY
子句中。对那些需要按其分组,并对其分组的聚合数据进行汇总的列,就请对这些列加上ROLLUP运算符。

注意: “GROUP BY
ROLLUP(col1,col2)”与“GROUP BY
ROLLUP(col1),ROLLUP(col2)”是有区别的。“GROUP BY
ROLLUP(col1),ROLLUP(col2)”其实就相当于“GROUP BY
CUBE(col1,col2)”,因为它对每个分组的聚合都要进行汇总。“GROUP BY
ROLLUP(col1,col2)”与“GROUP BY
ROLLUP(col2,col1)”也有区别,前者是对每个col1的唯一值都产生一个在col1下各个col2聚合值汇总的行,再对所有col1与col2的聚合值产生一个汇总行;而后者是对每个col2的唯一值都产生一个在col2下各个col1聚合值的汇总行,再对所有col1与col2的聚合值产生一个汇总行。这样说逻辑可能不太清晰,我们看一下下面的图表就一目了然了。

col1
col2
amount
 
 
 
 
 
 
 
col1
col2
amount
3
2
3584777
3
2
3584777
3
3
12774875
4
2
200789.1
3
 
16359652
5
2
274432
4
2
200789.1
 
2
4059998
4
3
8619498
3
3
12774875
4
 
8820288
4
3
8619498
5
2
274432
5
3
2024463
5
3
2024463
 
3
23418837
5
 
2298895
 
 
27478835
 
 
27478835
 
 
 
GROUP BY ROLLUP(col1,col2)的效果 
GROUP BY ROLLUP(col2,col1)的效果 
 

2.     
实际案例

我们现在就来看一个Oracle9i中的统计示例,示例如下:
2.1.   
统计要求

开发一个关于各烟叶等级的二次验级的原发件数、原发重量及验收重量的统计报表。其中,原发件数、原发重量和验收重量等列要求计算出各等级组别的小计和所有记录的合计。
2.2.   
我们通常的做法

1.用下面的SQL统计出初步的数据集。
 
SELECT  T1.TOBACCO_CLASS_NAME,
                 T4.TOBACCO_CLASS_TYPE,
                 NVL(SUM(T1.ORG_PIECE), 0) TOTAL_ORG_PIECE,
                 NVL(SUM(T1.ORG_WEIGHT), 0) TOTAL_ORG_WEIGHT,
                 NVL(SUM(T1.AMOUNT), 0) TOTAL_AMOUNT
   FROM  VI_FK_BALANCE_DETAIL T1, TB_TOBACCO_CLASS T4
WHERE  T1.TOBACCO_CLASS_ID=T4.TOBACCO_CLASS_ID
                 AND T1.ACCOUNT_YEAR=T4.ACCOUNT_YEAR
                 AND T4.DEL_FLAG=0
                 AND T4.ENABLE_FLAG=0
                 AND T1.REC_DATE > TO_DATE(‘2006-11-05’, ‘YYYY-MM-DD’
GROUP  BY  T4.TOBACCO_CLASS_TYPE,T1.TOBACCO_CLASS_NAME
 ORDER   BY  T4.TOBACCO_CLASS_TYPE
查询的结果如下表所示

烟叶等级
等级组别
原发件数
原发重量

验收重量
(B1F)上桔一
51
4945
197800
197508.1
(B2F)上桔二
51
8335
333400
332316.9
(C1F)中桔一
51
694
27760
27610.54
(C2F)中桔二
51
803
32120
31650.4
(C3F)中桔三
51
6381
255240
255372.6
(X1F)下桔一
51
75
3000
3012.2
(B3F)上桔三
52
4701
188040
187389.9
(B4F)上桔四
52
122
4880
4866.81
(C3V)中微青三
52
174
6960
6934.06
(C4F)中桔四
52
4639
185560
185276.4
(X2F)下桔二
52
1739
69560
69029.79
(X2V)下微青二
52
26
1040
1038.34
(X3F)下桔三
52
1263
50520
50439.86
(X4F)下桔四
53
102
4080
4075.62
(B3K)上杂三
54
0
0
249.39
                            

2.再在程序中编写相应的方法对查询得到的数据集进行处理。
我们的重点不是在怎么写处理数据集的方法上,所以相应的方法在此略去。
 
 

2.3.     
用SQL直接实现的方法

 

SELECT DECODE(GROUPING(T4.TOBACCO_CLASS_TYPE) + GROUPING(T1.TOBACCO_CLASS_NAME),
                               1,
                               DECODE(T4.TOBACCO_TYPE,
                                                  51, ‘上等烟小计’,
                                                  52, ‘中等烟小计’,
                                                  53, ‘下等烟小计’,
                                                  54, ‘低等烟小计’,
                                                  ‘小计’),
                               2,
                               ‘合计’,
                               T1.TOBACCO_CLASS_NAME
                 ) TOBACCO_CLASS_NAME,
                   T4.TOBACCO_CLASS_TYPE,
                   NVL(SUM(T1.ORG_PIECE),0) TOTAL_ORG_PIECE,
                   NVL(SUM(T1.ORG_WEIGHT), 0) TOTAL_ORG_WEIGHT,
                   NVL(SUM(T1.AMOUNT), 0) TOTAL_AMOUNT
 FROM     VI_FK_BALANCE_DETAIL T1, TB_TOBACCO_CLASS T4
WHERE    T1.TOBACCO_CLASS_ID=T4.TOBACCO_CLASS_ID
                   AND T1.ACCOUNT_YEAR=T4.ACCOUNT_YEAR
                   AND T4.DEL_FLAG=0
                   AND T4.ENABLE_FLAG=0
                   AND T1.REC_DATE > TO_DATE(‘2006-11-05’, ‘YYYY-MM-DD’
GROUP   BY   ROLLUP( T4.TOBACCO_CLASS_TYPE,T1.TOBACCO_CLASS_NAME)
ORDER   BY  T4.TOBACCO_CLASS_TYPE
  

通过查询得到统计结果如下表所示,该表的统计结果已经满足了统计要求。

烟叶等级
等级组别
原发件数
原发重量

验收重量
(B1F)上桔一
51
4945
197800
197508.1
(B2F)上桔二
51
8335
333400
332316.9
(C1F)中桔一
51
694
27760
27610.54
(C2F)中桔二
51
803
32120
31650.4
(C3F)中桔三
51
6381
255240
255372.6
(X1F)下桔一
51
75
3000
3012.2
上等烟小计
51
21233
849320
847470.8
(B3F)上桔三
52
4701
188040
187389.9
(B4F)上桔四
52
122
4880
4866.81
(C3V)中微青三
52
174
6960
6934.06
(C4F)中桔四
52
4639
185560
185276.4
(X2F)下桔二
52
1739
69560
69029.79
(X2V)下微青二
52
26
1040
1038.34
(X3F)下桔三
52
1263
50520
50439.86
等烟小计
52
12664
506560
504975.1
(X4F)下桔四
53
102
4080
4075.62
下等烟小计
53
102
4080
4075.62
(B3K)上杂三
54
0
0
249.39
低等烟小计
54
0
0
249.39
合计
 
33999
1359960
1356771
 

 

    通过比较,相信大家也感觉到后者的独特魅力了吧。至少我在写那些对数据集处理得到小计行的方法的时候,感到虽不是很复杂,但也是有些繁琐的,远不如直接在SQL中实现小计来得潇洒、简洁。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息