Oracle实现行转列的几种思路

让人想犯罪 __ 提交于 2020-02-16 14:17:16

1.说明

这里主要介绍三种行转列的方式,其中方式一为传统的方式实现行转列,在这一节中我们分别介绍行转列中值为求个数、数字以及字符串三种方式;方式二主要借助11g新增加的函数pivot实现;方式三利用pivot和xml解决了方式二中硬编码的缺陷。

2.环境准备

2.1数据库版本

oracle版本:11g.2.0.4_x64

2.2 数据库初始化脚本

--创建数据表
create table stu(id int,name varchar2(20),course varchar(20),score int,lev varchar(5));
--插入数据
insert into stu(id,name,course,score,lev)
select 1,'张三','语文',90,'优' from dual
union select 2,'张三','数学',80,'良' from dual
union select 3,'张三','英语',70,'中'  from dual
union select 4,'李四','语文',60,'差'  from dual
union select 5,'李四','数学',91,'优'  from dual
union select 6,'李四','英语',81,'良'  from dual
union select 7,'王五','语文',71,'中'  from dual
union select 8,'王五','数学',61,'差'  from dual
union select 9,'王五','英语',51,'差'  from dual;
--数据提交
commit;

2.3 数据表内容

3.经典的实现方式

3.1 简述

主要是利用decode函数、聚合函数(如max、sum等)、group by分组实现的行转列的功能。此种方式主要针对oracle在11g之前没有提供pivot函数实现的方式,然而方式三的LISTARR也是11g出现的函数。

3.2 计算每个人记录科目的数量

3.2.1 Sql语句

select t.name, count(decode(t.course, '语文', 1)) as "语文",
               count(decode(t.course, '数学', 1)) as "数学",
               count(decode(t.course, '英语', 1)) as "英语"
from STU t group by t.name;

3.2.2 查询结果

3.2.3 decode介绍

1)语法

decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值);

2)例子

decode(字段或字段的运算,值1,值2,值3)

这个函数运行的结果是,当字段或字段的运算的值等于值1时,该函数返回值2,否则返回值3.当然值1,值2,值3也可以是表达式,这个函数使得某些sql语句简单了许多.

3.3 计算每个人记录科目的成绩

3.3.1 Sql语句

select t.name, sum(decode(t.course, '语文', score)) as "语文",
               sum(decode(t.course, '数学', score)) as "数学",
               sum(decode(t.course, '英语', score)) as "英语"
from STU t group by t.name;

3.3.2 结果

3.4 计算每个人记录科目的级别

3.4.1 Sql语句

select t.name, (LISTAGG(decode(t.course, '语文', t.lev),',') WITHIN group(order by t.course)) as "语文",
               (LISTAGG(decode(t.course, '数学', t.lev),',') WITHIN group(order by t.course)) as "数学",
               (LISTAGG(decode(t.course, '英语', t.lev),',') WITHIN group(order by t.course)) as "英语"
from STU t group by t.name;

3.4.2 查询结果

3.4.3 LISTAGG函数说明

1)作用

可以实现将多列记录聚合为一列记录,实现数据的压缩

2)语法

listagg(measure_expr,delimiter) within group ( order by order_by_clause);

1.listagg函数的第一个参数是需要显示的字段;

2.第二个参数是数值之间的分隔符;

3.同时还需要进行排序和分组within group (order by name)

4. PIVOT实现行转列

Oracle 11g后,出现PIVOT,更简便地实现“行转列”。使用前,需确定数据库环境大于11g,最好也确认下生产环境的数据库是否大于11g,避免项目后期出现状况。

4.1 计算每个人记录科目的数量

4.1.1 Sql

select * from (select t.name, t.course from stu t)  pivot(count(1) for course in ('语文', '数学', '英语'));

4.1.2 结果

4.2 计算每个人记录科目的成绩

4.2.1 Sql

select * from (select t.name, t.course, t.score from stu t)  pivot(sum(score) for course in ('语文', '数学', '英语'));

4.2.2 结果

4.3 计算每个人记录科目的级别

4.3.1 Sql

select * from (select t.name, t.course, t.lev from stu t)  pivot((LISTAGG(lev,',') WITHIN group(order by course)) for course in ('语文', '数学', '英语'));

4.3.2 结果

5 PIVOT结合XML实现行转列

使用经典的方法和PIVOT方法,DEPTNO的参数是硬编码的。而通过PIVOT XML能解决这一问题,使分列条件可以是动态的。但,输出的是XML的CLOB的格式。这里只是简单说明一下。

5.1 Sql

select * from (select t.name, t.course from stu t) pivot xml (count(1) for course in (select course from stu));

5.2 结果

我们很容易看出第二列是一个xml字符串,我们先看一下xml的内容:

<PivotSet>
    <item>
        <column name="COURSE">数学</column>
        <column name="COUNT(1)">1</column>
    </item>
    <item>
        <column name="COURSE">英语</column>
        <column name="COUNT(1)">1</column>
    </item>
    <item>
        <column name="COURSE">语文</column>
        <column name="COUNT(1)">1</column>
    </item>
</PivotSet>

这样我们可以通过解析xml也可以得到相同的结果。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!