加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Oracle中行转列、列转行的实现方法详解

(2017-04-24 11:00:01)
标签:

oracle行转列方法

oracle列转行方法

pivot函数用法示例

oracle行列转换示例

unpivot函数用法示例

分类: Oracle数据库
       在Oracle表数据处理的过程中,为了更好的展示数据,我们会遇到将表的行转换成列或将表的列转换成行的方式来形成交叉表报表,可能可以更好地显示这些数据。
       通过转换展现方式,能更加直观、方便地查看报表数据。那在Oracle 中是如何实现的呢?下面我们来看看具体的应用示例吧。

一、创建测试表
drop table t_test_fee;
create table t_test_fee(
pno      integer,
p_code   varchar2(30),
p_cost   number
)

insert into t_test_fee(pno,p_code,p_cost)
select 100001,'010',89.03 from dual
union all
select 100001,'011',103.01 from dual
union all
select 100001,'019',58.08 from dual
union all
select 100001,'047',94.32 from dual
union all
select 100001,'055',61.74 from dual
union all
select 100001,'068',79.81 from dual
union all
select 100001,'011',100.39 from dual
;
commit;

select * from t_test_fee

二、行转列的方法
2.1、通过 decode 函数实现行转列,适用范围:oracle 8i,9i,10g及以后版本
select pno,
sum(decode(p_code, '010', p_cost)) "010",
sum(decode(p_code, '011', p_cost)) "011",
sum(decode(p_code, '019', p_cost)) "019",
sum(decode(p_code, '047', p_cost)) "047",
sum(decode(p_code, '055', p_cost)) "055",
sum(decode(p_code, '068', p_cost)) "068"
from t_test_fee
group by pno
order by pno asc


2.2、通过 pivot 函数实现行转列,适用范围:oracle 11g及以后
select *
from t_test_fee
  pivot (
  sum(nvl(p_cost,0))
  for p_code          
  in  ('010' as "010",'011' as "011",'019' as "019",'047' as "047",'055' as "055",'068' as "068")
) order by pno asc;
注意:如果聚合函数与 PIVOT 一起使用,则计算聚合时将不考虑出现在值列中的任何空值。

2.3、通过动态拼接sql处理实现行转列
declare
   sqlstr varchar2(8000):= '';
begin
   execute immediate 'select wm_concat(''''''''||p_code||'''''''') 
   from (
   select distinct p_code from t_test_fee order by p_code
   ) t' into sqlstr;

   sqlstr:='
   create or replace view tmp_result as
   select *
from t_test_fee
  pivot (
  sum(nvl(p_cost,0))
  for p_code          
  in ('||sqlstr||')
) order by pno asc';
  execute immediate sqlstr;
end;
--这里把查询结果放到了视图tmp_result里,查看这个视图就可以了。
select * from tmp_result;


2.4、通过聚合函数 sum 实现行转列
select pno,sum(case when p_code='010' then p_cost else 0 end) "010",
sum(case when p_code='011' then p_cost else 0 end) "011",
sum(case when p_code='019' then p_cost else 0 end) "019",
sum(case when p_code='047' then p_cost else 0 end) "047",
sum(case when p_code='055' then p_cost else 0 end) "055",
sum(case when p_code='068' then p_cost else 0 end) "068"
from t_test_fee
group by pno;

2.5、通过 pivot xml 函数来实现,结果将以xml格式输出。
-- 允许使用 any 关键字
select *
from t_test_fee
  pivot xml (
  sum(nvl(p_cost,0))
  for p_code          
  in (any)
) order by pno asc;

-- 允许使用子查询
select *
from t_test_fee
  pivot xml (
  sum(nvl(p_cost,0))
  for p_code          
  in (select p_code from t_test_fee)
) order by pno asc;



三、列转行的方法
3.1、通过 listagg 函数实现列转行
with tab1 as(
  select 'China' nation ,'Guangzhou' city from dual union all
  select 'China' nation ,'Shanghai' city from dual union all
  select 'China' nation ,'Beijing' city from dual union all
  select 'USA' nation ,'New York' city from dual union all
  select 'USA' nation ,'Bostom' city from dual union all
  select 'Japan' nation ,'Tokyo' city from dual 
)
select nation,listagg(city,',') within group (order by city)
from tab1
group by nation

3.2、通过 listagg 和 rank 函数实现行转列
with tab1 as(
  select 500 population, 'China' nation ,'Guangzhou' city from dual union all
  select 1500 population, 'China' nation ,'Shanghai' city from dual union all
  select 500 population, 'China' nation ,'Beijing' city from dual union all
  select 1000 population, 'USA' nation ,'New York' city from dual union all
  select 500 population, 'USA' nation ,'Bostom' city from dual union all
  select 500 population, 'Japan' nation ,'Tokyo' city from dual 
)
select population,
       nation,
       city,
       listagg(city,',') within GROUP (order by city) over (partition by nation) rank
from tab1

3.3、通过 wm_concat 函数实现列转行
with tab1 as(  
  select 'China' nation ,'Guangzhou' city from dual union all  
  select 'China' nation ,'Shanghai' city from dual union all  
  select 'China' nation ,'Beijing' city from dual union all  
  select 'USA' nation ,'New York' city from dual union all  
  select 'USA' nation ,'Bostom' city from dual union all  
  select 'Japan' nation ,'Tokyo' city from dual   
)  
select nation,wm_concat(city) 
from tab1  
group by nation

3.4、通过 union all 函数实现列转行
with tab1 as (
select 23 as cnt1,100 as cnt2,300 as cnt3,500 as cnt4,800 as  cnt5,1024 as  cnt6,6721 as cnt7,890 as cnt8 from dual
)
select cnt1 from tab1 
union all
select cnt2 from tab1 
union all
select cnt3 from tab1 
union all
select cnt4 from tab1 
union all
select cnt5 from tab1 
union all
select cnt6 from tab1 
union all
select cnt7 from tab1 
union all
select cnt8 from tab1 
;

3.5、通过 unpivot 函数实现列转行
with tab1 as (
select 23 as cnt1,100 as cnt2,300 as cnt3,500 as cnt4,800 as  cnt5,1024 as  cnt6,6721 as cnt7,890 as cnt8 from dual
)
select jk_cnt 
from tab1 
unpivot (jk_cnt for xm_name in (cnt1,cnt2,cnt3,cnt4,cnt5,cnt6,cnt7,cnt8))
;

注意:UNPIVOT 并不完全是 PIVOT 的逆操作。 PIVOT 会执行一次聚合,从而将多个可能的行合并为输出中的单个行。 而 UNPIVOT 不会重现原始表值表达式的结果,因为行已经被合并了。 另外,UNPIVOT 的输入中的 null 值不会显示在输出中,而在执行 PIVOT 操作之前,输入中可能有原始的 null 值。


四、总结
      Pivot 为 SQL 语言增添了一个非常重要且实用的功能。您可以使用 pivot 函数针对任何关系表创建一个交叉表报表,而不必编写包含大量 decode 函数的令人费解的、不直观的代码。同样,您可以使用 unpivot 操作转换任何交叉表报表,以常规关系表的形式对其进行存储。 Pivot 可以生成常规文本或 XML 格式的输出。如果是 XML 格式的输出,您不必指定 pivot 操作需要搜索的值域。

       在以上的示例方法中,采用decode和union all的方式比较直观,但需要更多的代码来实现;所以一般我们比较常用的还是pivot和unpivot函数。




本文参考资料:http://www.oracle.com/technetwork/cn/articles/11g-pivot-101924-zhs.html

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有