使用pivot/unpivot/wmconcat/listagg等进行‘行列转换’之详细解析

闲话少说,直入主题!

此文是基于其他博客部分框架以及大致内容进行了个人层面的详细分析和改进。

1. wmconcat
同一列的列值,根据相应分组规则 ,将各自组内的值,存于同一个单元格里,存于clob字段中,以','间隔;
如果直接使用wmconcat而没有分组,则是将同一个列的值,转换后都存于同一个单元格里,默认是以逗号','间隔,可以改变。

(1)创建测试表并插入数据

create table test_wm_concat(id number,name varchar2(20));  
insert into test_wm_concat values(1,'a');  
insert into test_wm_concat values(1,'b');  
insert into test_wm_concat values(1,'c');  
insert into test_wm_concat values(2,'d');  
insert into test_wm_concat values(2,'e'); 

(2)查询测试表test_wm_concat的数据

select * from test_wm_concat;

   

(3)使用wm_concat查询数据(直接查询以及分组后查询)

select wm_concat(name) name from test_wm_concat;

   

       可以通过to_char将clob转成varchar2的形式

select to_char(wm_concat(name)) name from test_wm_concat;

    

      按照id分组,合并name,同组的存于一个clob字段中

select id, wm_concat(name) name from test_wm_concat group by id;

   

(4)使用wm_concat查询数据,存于clob字段中,以'|'间隔,而默认是','

select replace(wm_concat(name), ',', '|') name from test_wm_concat;

   

(5)使用wm_concat和decode组合将列按照列值,拆分成n个列展示(笨方法);
     想根据哪个字段展示哪个值,在decode里自由选择即可;

     将clob字段to_char转成字符型;

SELECT to_char(WM_CONCAT(a)) a,
       to_char(WM_CONCAT(b)) b,
       to_char(WM_CONCAT(c)) c,
       to_char(WM_CONCAT(d)) d,
       to_char(WM_CONCAT(e)) e
  FROM (SELECT DECODE(name, 'a', id, NULL) a,
               DECODE(name, 'b', id, NULL) b,
               DECODE(name, 'c', id, NULL) c,
               DECODE(name, 'd', id, NULL) d,
               DECODE(name, 'e', id, NULL) e
          FROM test_wm_concat);

   

(6)对wm_concat转换后的单元格进行解析,将以逗号区分的n个值,拆分回n行展示;

        也就是解析clob字段,将存于同一个clob字段的多值,解析成多行数据(以回车为间隔)。

select * from table(splitstr_rows((select replace(wm_concat(name),',',chr(10)) from test_wm_concat), chr(10)));

  

(7)wmconcat实际应用案例
        比如根据基表创建时视图,基表有多个字段,类似"create or replace view as select 字段1,...字段n from tablename",
        使用wm_concat可以快速取出这些字段。

        假设我的emp表中有(employee_id .... department_id)11个字段。查询结果如下:

 select column_name
  from user_tab_columns
 where table_name = 'EMP';

   

select to_char('create or replace view as select ' ||
               wm_concat(column_name) || ' from emp;') sqlStr
  from user_tab_columns
 where table_name = 'EMP';


2.listagg
listagg与wmconcat效果类似,都是将列值存于同一个单元格里,但是listagg更灵活,可以进行排序等操作。
(1)排序操作:直接使用wmconcat和 listagg within group 进行比对

select to_char(wm_concat(employee_id)) from emp;
 
select (listagg(employee_id, ',')  within group(order by employee_id)) employee_id
  from emp;
 

(2)分组后排序操作:使用分组统计各个部门的所有员工列表。

select department_id,
       (listagg(employee_id, ' ,') within group(order by employee_id)) employee_id
  from emp
 group by department_id;
 
(3)还可以与分析函数等组合操作


3.
pivot,行转列(把一列根据列值拆分成多列)
pivot(聚合函数 for 列名 in(类型)),其中 in('') 中可以指定别名;
(1)创建测试表并插入数据

测试数据 (id,类型名称,销售数量)

create table demo(id int,name varchar(20),nums int);  
insert into demo values(1, '苹果', 1000);  
insert into demo values(2, '苹果', 2000);  
insert into demo values(3, '苹果', 4000);  
insert into demo values(4, '橘子', 5000);  
insert into demo values(5, '橘子', 3000);  
insert into demo values(6, '葡萄', 3500);  
insert into demo values(7, '芒果', 4200);  
insert into demo values(8, '芒果', 5500); 

(2)查询测试表数据

select * from demo;

 

(3)案例:根据水果的类型为列标题查询出一条数据显示出每种类型的销售数量。

笨方法1:使用这种方式,一定要构造出from 后的是  “新列名” 与 “展示值”  是 一对一 的关系

SELECT to_char(wm_concat(DECODE(name, '苹果', nums, NULL))) 苹果,
       to_char(wm_concat(DECODE(name, '橘子', nums, NULL))) 橘子,
       to_char(wm_concat(DECODE(name, '葡萄', nums, NULL))) 葡萄,
       to_char(wm_concat(DECODE(name, '芒果', nums, NULL))) 芒果
  FROM (select name, sum(nums) nums from demo group by name);

笨方法2:多项子查询 

select *
  from (select sum(nums) 苹果 from demo where name = '苹果'),
       (select sum(nums) 橘子 from demo where name = '橘子'),
       (select sum(nums) 葡萄 from demo where name = '葡萄'),
       (select sum(nums) 芒果 from demo where name = '芒果');

笨方法3:利用decode 函数

select sum(decode(name, '苹果', nums)) 苹果,
       sum(decode(name, '橘子', nums)) 橘子,
       sum(decode(name, '葡萄', nums)) 葡萄,
       sum(decode(name, '芒果', nums)) 芒果
  from demo;

简便方法:使用pivot (把一列根据列值拆分成多个列值列)

select *
  from (select name, nums from demo) pivot(sum(nums) for name in('苹果' 苹果,
                                                                 '橘子' 橘子,
                                                                 '葡萄' 葡萄,
                                                                 '芒果' 芒果));

  

4.
unpivot,列转行 (把多列合成一列按行展示)

(1)创建测试表并插入数据

create table Fruit(id int,name varchar(20), Q1 int, Q2 int, Q3 int, Q4 int);  
insert into Fruit values(1,'苹果',1000,2000,3300,5000);  
insert into Fruit values(2,'橘子',3000,3000,3200,1500);  
insert into Fruit values(3,'香蕉',2500,3500,2200,2500);  
insert into Fruit values(4,'葡萄',1500,2500,1200,3500);  

(2)查询测试表数据

select * from Fruit;

   

(3)案例:水果表里记录了4个季度的销售数量,现在要将每种水果的每个季度的销售情况用多行数据展示。

select id, name, jidu, xiaoshou
  from Fruit unpivot(xiaoshou for jidu in(q1, q2, q3, q4));

  

效果相同的笨方法:

select id, name, 'Q1' jidu, (select q1 from fruit where id = f.id) xiaoshou
  from Fruit f
union
select id, name, 'Q2' jidu, (select q2 from fruit where id = f.id) xiaoshou
  from Fruit f
union
select id, name, 'Q3' jidu, (select q3 from fruit where id = f.id) xiaoshou
  from Fruit f
union
select id, name, 'Q4' jidu, (select q4 from fruit where id = f.id) xiaoshou

  from Fruit f;

5.

OVER。





猜你喜欢

转载自blog.csdn.net/dboy_willow/article/details/81001008