oracle行列互转常用小技巧总结
平时做报表统计数据时,常遇到行列互转,最后有总计等要求的报表式。 注:下面的sql都是在oracle 10g下写的。 假如现有一张这样的数据表: SELECT * FROM studentscores ; 多行转多列 现客户要求这样的式显示 这样的式来显示成绩。 方法一: WITH t1 AS( SEL
平时做报表统计数据时,常遇到行列互转,最后有总计等要求的报表格式。
注:下面的sql都是在oracle 10g下写的。
假如现有一张这样的数据表:
SELECT * FROM studentscores ;
多行转多列
现客户要求这样的格式显示
这样的格式来显示成绩。
方法一:
WITH t1 AS( SELECT st1.name NAME,st1.score chinese ,0 math, 0 english FROM studentscores st1 WHERE st1.object = '语文' ), t2 AS( SELECT st2.name NAME,0 chinese ,st2.score math, 0 english FROM studentscores st2 WHERE st2.object = '数学' ), t3 AS( SELECT st3.name NAME,0 chinese ,0 math, st3.score english FROM studentscores st3 WHERE st3.object = '英语' ) SELECT t.name 姓名, SUM(t.chinese) 语文, SUM(t.math) 数学, SUM(t.english) 英语 FROM( SELECT t1.name,t1.chinese,t1.math,t1.english FROM t1 UNION ALL SELECT t2.name,t2.chinese,t2.math,t2.english FROM t2 UNION ALL SELECT t3.name,t3.chinese,t3.math,t3.english FROM t3 )t。 GROUP BY t.name
这种方法易理解,但是麻烦,如果学科有非常多的时候,那就麻烦到要命了。
方法二
SELECT st.NAME 姓名, SUM(DECODE(st.object,'语文',st.score,0)) 语文, SUM(DECODE(st.object,'数学',st.score,0)) 数学, SUM(DECODE(st.object,'英语',st.score,0)) 英语 FROM studentscores st GROUP BY st.NAME ;方法二对于新手来说,也许不能一下子弄明白,不妨这样来想想。如果我要求你统计每个学生的总分,你是不是很快就可以写出来了select st.name,sum(st.score) from studentscores group by name.那么在这条语句的基础上,我改一改select st.name,sum(decode(st.object,'语文',st.score,0)) 语文 from studentscores st.是不是就只选择语文了,呵呵
多行转一列
现在要求这样的显示格式:
多行转成一列的字符串,这让我们很容易想到oralce中的wm_concat函数的使用
SELECT st.name , wm_concat(st.object || '(' || st.score || ')') FROM studentscores st GROUP BY st.name;
一列转多行
SELECT regexp_substr(t.str,'[^,]+',1,ROWNUM) VALUE FROM(SELECT 'a,b,c,d' str FROM dual) t CONNECT BY ROWNUM
可看我的另一篇博文oracle实现类型split效果列合计
需求效果图:
方法一
WITH t1 AS( SELECT st.NAME 姓名, SUM(DECODE(st.object,'语文',st.score,0)) 语文, SUM(DECODE(st.object,'数学',st.score,0)) 数学, SUM(DECODE(st.object,'英语',st.score,0)) 英语 FROM studentscores st GROUP BY st.NAME ORDER BY st.name DESC ), t2 AS( SELECT '合计' 姓名, SUM(DECODE(st.object,'语文',st.score,0)) 语文, SUM(DECODE(st.object,'数学',st.score,0)) 数学, SUM(DECODE(st.object,'英语',st.score,0)) 英语 FROM studentscores st ) SELECT t1.* FROM t1 UNION ALL SELECT t2.* FROM t2使用方法一体现不出高手风范,来看看方法二
方法二
SELECT decode(grouping(st.NAME),1,'总计',st.name) 姓名, SUM(DECODE(st.object,'语文',st.score,0)) 语文, SUM(DECODE(st.object,'数学',st.score,0)) 数学, SUM(DECODE(st.object,'英语',st.score,0)) 英语 FROM studentscores st GROUP BY ROLLUP(st.NAME) ORDER BY st.name
呵呵,是不是觉得高深莫测!!!这需要你先弄明白rollup,grouping是干嘛的才行,具体细节可参考我的另一篇博文oralce之rollup&grouping
在这简单说说,group by rollup(st.name)
select * from xxx group by st.name
union all
select * from xxx
就像方法一那样,先group by st.name得到t1,然后不需要group by求总的得到t2。
GROUPING函数可以接受一列,该列必须是group by中出现的,返回0或者1。如果列值为空,那么GROUPING()返回1;如果列值非空,那么返回0。
行合计
效果图如下:
学习了上面的行转列之后,也许你马上就想到这样子来
方法一:
WITH st AS( SELECT st1.name,st1.object,st1.score FROM studentscores st1 UNION ALL SELECT st2.name,'总计',SUM(st2.score) FROM studentscores st2 GROUP BY st2.name ) SELECT st.NAME 姓名, SUM(DECODE(st.object,'语文',st.score,0)) 语文, SUM(DECODE(st.object,'数学',st.score,0)) 数学, SUM(DECODE(st.object,'英语',st.score,0)) 英语, SUM(DECODE(st.object,'总计',st.score,0)) 总计 FROM st GROUP BY st.NAME ;嗯,这样也是不失为一张方法,但是也不用这么麻烦
方法二
SELECT st.NAME 姓名, SUM(DECODE(st.object,'语文',st.score,0)) 语文, SUM(DECODE(st.object,'数学',st.score,0)) 数学, SUM(DECODE(st.object,'英语',st.score,0)) 英语, SUM(st.score) 总计 FROM studentscores st GROUP BY st.NAME ;行列合计
SELECT decode(grouping(st.NAME),1,'总计',st.name) 姓名, SUM(DECODE(st.object,'语文',st.score,0)) 语文, SUM(DECODE(st.object,'数学',st.score,0)) 数学, SUM(DECODE(st.object,'英语',st.score,0)) 英语, SUM(st.score) 合计 FROM studentscores st GROUP BY ROLLUP(st.NAME) ORDER BY st.name
一些报表有些需要更复杂,比如每一种分类都有一个小计,最后再来一个合计,这个可学习我的另一篇博文
oracle之rollup&cube&grouping