您的位置:首页 > 数据库 > Oracle

oracle行列互转常用小技巧总结

2014-06-07 00:59 316 查看
平时做报表统计数据时,常遇到行列互转,最后有总计等要求的报表格式。

注:下面的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 <= LENGTH(regexp_replace(t.str,'[^,]+'))+1;



可看我的另一篇博文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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: