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

      平时做报表统计数据时,常遇到行列互转,最后有总计等要求的报表格式。

     注:下面的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


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值