Oracle行转列、列转行的Sql语句计算上海时时乐走

将Emp1, Emp2, Emp3, Emp4, Emp5的列名和列值存储到字段:Employee和Orders中

效果3: 按ID分组合并name

 SQL Code 

1

  

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

   

上海时时乐走势图官网 1

sql语句等同于下面的sql语句:

  SQL Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

  

-------- 适用范围:8i,9i,10g及以后版本  ( MAX   DECODE )
select id,
       max(decode(rn, 1, name, null)) ||
       max(decode(rn, 2, ',' || name, null)) ||
       max(decode(rn, 3, ',' || name, null)) str
  from (select id,
               name,
               row_number() over(partition by id order by name) as rn
          from test) t
 group by id
 order by 1;
-------- 适用范围:8i,9i,10g及以后版本 ( ROW_NUMBER   LEAD )
select id, str
  from (select id,
               row_number() over(partition by id order by name) as rn,
               name || lead(',' || name, 1) over(partition by id order by name) ||
               lead(',' || name, 2) over(partition by id order by name) || 
               lead(',' || name, 3) over(partition by id order by name) as str
          from test)
 where rn = 1
 order by 1;
-------- 适用范围:10g及以后版本 ( MODEL )
select id, substr(str, 2) str
  from test model return updated rows partition by(id) dimension by(row_number() 
  over(partition by id order by name) as rn) measures(cast(name as varchar2(20)) as str) 
  rules upsert iterate(3) until(presentv(str [ iteration_number   2 ], 1, 0) = 0)
  (str [ 0 ] = str [ 0 ] || ',' || str [ iteration_number   1 ])
 order by 1;
-------- 适用范围:8i,9i,10g及以后版本 ( MAX   DECODE )
select t.id id, max(substr(sys_connect_by_path(t.name, ','), 2)) str
  from (select id, name, row_number() over(partition by id order by name) rn
          from test) t
 start with rn = 1
connect by rn = prior rn   1
       and id = prior id
 group by t.id;

   

Pivot旋转的作用,是将关系表(table_source)中的列(pivot_column)的值,转换成另一个关系表(pivot_table)的列名:

结论

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

上海时时乐走势图官网 2上海时时乐走势图官网 3

效果2: 把结果里的逗号替换成"|"

 SQL Code 

1

  

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

   

上海时时乐走势图官网 4

select p.name,p.math,p.phy
from dbo.usr u
pivot
(
    sum(score)
    for class in([math],[phy]) 
) as p

XML类型

上述pivot列转行示例中,你已经知道了需要查询的类型有哪些,用in()的方式包含,假设如果您不知道都有哪些值,您怎么构建查询呢?

pivot 操作中的另一个子句 XML 可用于解决此问题。该子句允许您以 XML 格式创建执行了 pivot 操作的输出,在此输出中,您可以指定一个特殊的子句 ANY 而非文字值

示例如下:

 SQL Code 

1
2
3
4
5
6
7

  

select * from (
   select name, nums as "Purchase Frequency"
   from demo t
)                              
pivot xml (
   sum(nums) for name in (any)
)

上海时时乐走势图官网 5

如您所见,列 NAME_XML 是 XMLTYPE,其中根元素是 <PivotSet>。每个值以名称-值元素对的形式表示。您可以使用任何 XML 分析器中的输出生成更有用的输出。

上海时时乐走势图官网 6

对于该xml文件的解析,贴代码如下:

  SQL Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

 

create or replace procedure ljz_pivot_xml_sp(pi_table_name   varchar2,
                                             pi_column_name  varchar2,
                                             pi_create_table varchar2) as
  v_column      nvarchar2(50);
  v_count       number := 0;
  v_i           number;
  v_parent_node nvarchar2(4000);
  v_child_node  nvarchar2(4000);
  v_over        boolean := false;
  v_tmp         nvarchar2(50);
  v_existsnode  number;
  v_sql         clob;
  v_name        varchar2(30);
  v_name_xml    xmltype;
begin
  v_sql         := 'select x.* from ' || pi_table_name ||
                   ' a, xmltable(''/PivotSet'' passing a.' ||
                   pi_column_name || ' columns ';
  v_parent_node := '/PivotSet';
  v_child_node  := 'item[1]/column[2]';
  v_i           := 1;
  execute immediate 'select ' || pi_column_name || ' from ' ||
                    pi_table_name || ' where rownum=1'
    into v_name_xml;
  select existsnode(v_name_xml,
                    '/PivotSet/item[' || to_char(v_i) || ']/column[1]')
    into v_existsnode
    from dual;
  while v_existsnode = 1 loop
    execute immediate 'select substr(extractvalue(' || pi_column_name ||
                      ', ''/PivotSet/item[' || to_char(v_i) || ']/column[1]''),1,30)
    from ' || pi_table_name || ' x'
      into v_name;
    v_sql := v_sql || '"' || v_name || '" varchar2(30) path ''item[' ||
             to_char(v_i) || ']/column[2]'',';
    v_i   := v_i   1;
    select existsnode(v_name_xml,
                      '/PivotSet/item[' || to_char(v_i) || ']/column[1]')
      into v_existsnode
      from dual;
  end loop;
  v_sql := trim(',' from v_sql) || ') x';
  commit;
  select count(1)
    into v_count
    from user_tab_columns
   where table_name = upper(pi_create_table);
  if v_count = 0 then
    execute immediate 'create table ' || pi_create_table || ' as ' || v_sql;
  end if;
end;

 

第一个参数为要解析xml文件所属数据表,第二个参数为要解析xml所存字段,第三个参数存放解析后的数据集。

测试:

begin

ljz_pivot_xml_sp('(select * from (select deptno,sal from emp) pivot xml(sum(sal) for deptno in(any)))',

'deptno_xml',

'ljz_pivot_tmp');

end;

上海时时乐走势图官网 7

初学oracle xml解析,这种方法较为笨拙,一个一个循环列,原型如下:

select extractvalue(name_xml, '/PivotSet/item[1]/column[1]')

from (select * from (select name,nums from demo) pivot xml(sum(nums) for name in(any))) x

where existsnode(name_xml, '/PivotSet/item[1]/column[1]') = 1;

上海时时乐走势图官网 8

select x.*

from (select *

from (select name, nums from demo)

pivot xml(sum(nums)

for name in(any))) a,

xmltable('/PivotSet' passing a.name_xml columns

芒果 varchar2(30) path 'item[1]/column[2]',

苹果 varchar2(30) path 'item[2]/column[2]') x

上海时时乐走势图官网 9

不知是否存在直接进行解析的方法,这种方法还不如直接行列转变,不通过xml转来转去。

select '''' || listagg(substr(name, 1, 30), q'{','}') within group(order by name) || ''''

from (select distinct name from demo);

上海时时乐走势图官网 10

select *

from (select name, nums from demo)

pivot(sum(nums)

for name in('苹果', '橘子', '葡萄', '芒果'));

上海时时乐走势图官网 11

这样拼接字符串反而更加方便。

上海时时乐走势图官网 12

懒人扩展用法:

案例: 我要写一个视图,类似"create or replace view as select 字段1,...字段50 from tablename" ,基表有50多个字段,要是靠手工写太麻烦了,有没有什么简便的方法? 当然有了,看我如果应用wm_concat来让这个需求变简单,假设我的APP_USER表中有(id,username,password,age)4个字段。查询结果如下

 SQL Code 

1
2
3
4
5

  

/** 这里的表名默认区分大小写 */
select 'create or replace view as select ' || wm_concat(column_name) ||
       ' from APP_USER' sqlStr
  from user_tab_columns
 where table_name = 'APP_USER';

   

上海时时乐走势图官网 13

利用系统表方式查询

 SQL Code 

1

  

select * from user_tab_columns

上海时时乐走势图官网 14

wm_concat函数

首先让我们来看看这个神奇的函数wm_concat(列名),该函数可以把列值以","号分隔起来,并显示成一行,接下来上例子,看看这个神奇的函数如何应用准备测试数据

 SQL Code 

1
2
3
4
5
6

  

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

透视操作的处理流程是:

多行转字符串

这个比较简单,用||或concat函数可以实现

 SQL Code 

1
2

  

select concat(id,username) str from app_user
select id||username str from app_user

 

字符串转多列

实际上就是拆分字符串的问题,可以使用 substr、instr、regexp_substr函数方式

1,创建示例数据

pivot 列转行

测试数据 (id,类型名称,销售数量),案例:根据水果的类型查询出一条数据显示出每种类型的销售数量。

 SQL Code 

1
2
3
4
5
6
7
8
9

  

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);

   

上海时时乐走势图官网 15

分组查询 (当然这是不符合查询一条数据的要求的)

 SQL Code 

1

  

select name, sum(nums) nums from demo group by name

上海时时乐走势图官网 16

行转列查询

 SQL Code 

1

  

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

上海时时乐走势图官网 17

注意: pivot(聚合函数 for 列名 in(类型)) ,其中 in('') 中可以指定别名,in中还可以指定子查询,比如 select distinct code from customers

当然也可以不使用pivot函数,等同于下列语句,只是代码比较长,容易理解

 SQL Code 

1
2
3
4
5

  

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,pivot的等价写法:使用case when语句实现

unpivot 行转列

顾名思义就是将多列转换成1列中去
案例:现在有一个水果表,记录了4个季度的销售数量,现在要将每种水果的每个季度的销售情况用多行数据展示。

创建表和数据

 SQL Code 

1
2
3
4
5
6

  

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);
select * from Fruit

上海时时乐走势图官网 18

列转行查询

 SQL Code 

1

  

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

注意: unpivot没有聚合函数,xiaoshou、jidu字段也是临时的变量

上海时时乐走势图官网 19

同样不使用unpivot也可以实现同样的效果,只是sql语句会很长,而且执行速度效率也没有前者高

 SQL Code 

1
2
3
4
5
6
7

  

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

View Code

字符串转多行

使用union all函数等方式

declare @sql nvarchar(max)
declare @columnlist nvarchar(max)

set @columnlist=N''

;with cte as
(
select distinct class
from dbo.usr
)
select @columnlist ='sum(case when u.class=''' cast(class as varchar(10)) N''' then u.score else null end) as [' cast(class as varchar(10)) N'],'
from cte

select @columnlist=SUBSTRING(@columnlist,1,len(@columnlist)-1)

select @sql=
N'select u.name,'
     @columnlist
 N'from dbo.usr u
group by u.name'

exec(@sql)

Oracle 11g 行列互换 pivot 和 unpivot 说明

在Oracle 11g中,Oracle 又增加了2个查询:pivot(行转列) 和unpivot(列转行)

参考:)

google 一下,网上有一篇比较详细的文档:

4,动态unpivot的实现,使用动态sql语句

效果1 : 行转列 ,默认逗号隔开

 SQL Code 

1

  

select wm_concat(name) name from test;

   

上海时时乐走势图官网 20

参考文档:

一,Pivot用法

上海时时乐走势图官网 21上海时时乐走势图官网 22

2,unpivot用法示例

  • pivot将table_source旋转成透视表(pivot_table)之后,不能再被引用
  • pivot_column的列值,必须使用中括号([])界定符
  • 必须显式命名pivot_table的别名

在TSQL中,使用Pivot和Unpivot运算符将一个关系表转换成另外一个关系表,两个命令实现的操作是“相反”的,但是,pivot之后,不能通过unpivot将数据还原。这两个运算符的操作数比较复杂,记录一下自己的总结,以后用到时,作为参考。

2,对name进行分组,对score进行聚合,将class列的值转换为列名

逆透视(unpivot)的处理流程是:

Script1,使用case-when子句实现

SELECT VendorID, Employee, Orders  
FROM dbo.Venders as p 
UNPIVOT  
(Orders FOR Employee IN   
      (Emp1, Emp2, Emp3, Emp4, Emp5)  
)AS unpvt;  
GO 

聪明如你,很容易实现,代码就不贴了....

静态pivot写法的弊端是:如果pivot_column的列值发生变化,静态pivot不能对新增的列值进行透视,变通方法是使用动态sql,拼接列值

table_soucr
unpivot
(
newcolumn_store_unpivotcolumn_name for 
newcolumn_store_unpivotcolumn_value in (unpivotcolumn_name_list)  
)

在使用透视命令时,需要注意:

table_source
pivot
(
  aggregation_function(aggregated_column)
  for pivot_column in ([pivot_column_value_list])
) as pivot_table_alias

1,创建示例数据

二,Unpivot用法

  1. 对pivot_column和 aggregated_column的其余column进行分组,即,group by other_columns;
  2. 当pivot_column值等于某一个指定值,计算aggregated_column的聚合值;
use tempdb
go 

drop table if exists dbo.usr
go

create table dbo.usr
(
    name varchar(10),
    score int,
    class varchar(8)
)
go

insert into dbo.usr
values('a',20,'math'),('b',21,'math'),('c',22,'phy'),('d',23,'phy')
,('a',22,'phy'),('b',23,'phy'),('c',24,'math'),('d',25,'math')
go

3,unpivot可以使用union all来实现

上海时时乐走势图官网 23

CREATE TABLE dbo.Venders 
(
    VendorID int, 
    Emp1 int, 
    Emp2 int,  
    Emp3 int, 
    Emp4 int, 
    Emp5 int
);  
GO 

INSERT INTO dbo.Venders VALUES (1,4,3,5,4,4);  
INSERT INTO dbo.Venders VALUES (2,4,1,5,5,5);  
INSERT INTO dbo.Venders VALUES (3,4,3,5,4,4);  
INSERT INTO dbo.Venders VALUES (4,4,2,5,5,4);  
INSERT INTO dbo.Venders VALUES (5,5,1,5,5,5);  
GO 

unpivot是将列名转换为列值,列名做为列值,因此,会新增两个column:一个column用于存储列名,一个column用于存储列值

Script2,使用pivot子句实现

declare @sql nvarchar(max)
declare @classlist nvarchar(max)

set @classlist=N''

;with cte as
(
    select distinct class
    from dbo.usr
)
select @classlist =N'[' cast(class as varchar(11)) N'],'
from cte

select     @classlist=SUBSTRING(@classlist,1,len(@classlist)-1)

select @sql=N'select p.name,' @classlist 
N' from dbo.usr u
PIVOT
(
    sum(score) 
    for class in(' @classlist N')
) as p'

exec (@sql)

上海时时乐走势图官网 24

View Code

pivot命令的执行流程很简单,使用caseh when子句实现pivot的功能

4,动态Pivot写法

Using PIVOT and UNPIVOT

三,性能讨论

select u.name,
    sum(case when u.class='math' then u.score else null end) as math,
    sum(case when u.class='phy' then u.score else null end) as phy
from dbo.usr u
group by u.name

上海时时乐走势图官网 25上海时时乐走势图官网 26

  1. unpivotcolumn_name_list是逆透视列的列表,其列值是相兼容的,能够存储在一个column中
  2. 保持其他列(除unpivotcolumn_name_list之外的所有列)的列值不变
  3. 依次将unpivotcolumn的列名存储到newcolumn_store_unpivotcolumn_name字段中,将unpivotcolumn的列值存储到newcolumn_store_unpivotcolumn_value字段中

使用group by子句对name列分组,使用 case when 语句将pivot_column的列值作为列名返回,并对aggregated_column计算聚合值。

View Code

select VendorID, 'Emp1' as Employee, Emp1 as Orders
from dbo.Venders
union all 
select VendorID, 'Emp2' as Employee, Emp2 as Orders
from dbo.Venders
union all 
select VendorID, 'Emp3' as Employee, Emp3 as Orders
from dbo.Venders
union all
select VendorID, 'Emp4' as Employee, Emp4 as Orders
from dbo.Venders
union all
select VendorID, 'Emp5' as Employee, Emp5 as Orders
from dbo.Venders

pivot和unpivot的性能不是很好,不要用来处理海量的数据

View Code

View Code

上海时时乐走势图官网 27上海时时乐走势图官网 28

上海时时乐走势图官网 29上海时时乐走势图官网 30

本文由上海时时乐走势图发布于上海时时乐走势图官网,转载请注明出处:Oracle行转列、列转行的Sql语句计算上海时时乐走

您可能还会对下面的文章感兴趣: