作为Oracle开发工程师,推荐大伙看看

PIVOT and UNPIVOT Operators in Oracle Database 11g Release 1

This article shows how to use the new PIVOT and UNPIVOT operators in 11g, as well as giving a pre-11g solution to the same problems.

Related articles.

PIVOT

The PIVOT operator takes data in separate rows, aggregates it and converts it into columns. To see the PIVOT operator in action we need to create a test table.

CREATE TABLE pivot_test (

id            NUMBER,

customer_id   NUMBER,

product_code  VARCHAR2(5),

quantity      NUMBER

);

INSERT INTO pivot_test VALUES (1, 1, 'A', 10);

INSERT INTO pivot_test VALUES (2, 1, 'B', 20);

INSERT INTO pivot_test VALUES (3, 1, 'C', 30);

INSERT INTO pivot_test VALUES (4, 2, 'A', 40);

INSERT INTO pivot_test VALUES (5, 2, 'C', 50);

INSERT INTO pivot_test VALUES (6, 3, 'A', 60);

INSERT INTO pivot_test VALUES (7, 3, 'B', 70);

INSERT INTO pivot_test VALUES (8, 3, 'C', 80);

INSERT INTO pivot_test VALUES (9, 3, 'D', 90);

INSERT INTO pivot_test VALUES (10, 4, 'A', 100);

COMMIT;

So our test data starts off looking like this.

SELECT * FROM pivot_test;

ID CUSTOMER_ID PRODU   QUANTITY

---------- ----------- ----- ----------

1           1 A             10

2           1 B             20

3           1 C             30

4           2 A             40

5           2 C             50

6           3 A             60

7           3 B             70

8           3 C             80

9           3 D             90

10           4 A            100

10 rows selected.

SQL>

In its basic form the PIVOT operator is quite limited. We are forced to list the required values to PIVOT using the IN clause.

SELECT *

FROM   (SELECT product_code, quantity

FROM   pivot_test)

PIVOT  (SUM(quantity) AS sum_quantity FOR (product_code) IN ('A' AS a, 'B' AS b, 'C' AS c));

A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

-------------- -------------- --------------

210             90            160

1 row selected.

SQL>

If we want to break it down by customer, we simply include the CUSTOMER_ID column in the initial select list.

SELECT *

FROM   (SELECT customer_id, product_code, quantity

FROM   pivot_test)

PIVOT  (SUM(quantity) AS sum_quantity FOR (product_code) IN ('A' AS a, 'B' AS b, 'C' AS c))

ORDER BY customer_id;

CUSTOMER_ID A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

----------- -------------- -------------- --------------

1             10             20             30

2             40                            50

3             60             70             80

4            100

4 rows selected.

SQL>

Prior to 11g we could accomplish a similar result using the DECODE function combined with aggregate functions.

SELECT SUM(DECODE(product_code, 'A', quantity, 0)) AS a_sum_quantity,

SUM(DECODE(product_code, 'B', quantity, 0)) AS b_sum_quantity,

SUM(DECODE(product_code, 'C', quantity, 0)) AS c_sum_quantity

FROM   pivot_test

ORDER BY customer_id;

A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

-------------- -------------- --------------

210             90            160

1 row selected.

SQL>

SELECT customer_id,

SUM(DECODE(product_code, 'A', quantity, 0)) AS a_sum_quantity,

SUM(DECODE(product_code, 'B', quantity, 0)) AS b_sum_quantity,

SUM(DECODE(product_code, 'C', quantity, 0)) AS c_sum_quantity

FROM   pivot_test

GROUP BY customer_id

ORDER BY customer_id;

CUSTOMER_ID A_SUM_QUANTITY B_SUM_QUANTITY C_SUM_QUANTITY

----------- -------------- -------------- --------------

1             10             20             30

2             40              0             50

3             60             70             80

4            100              0              0

4 rows selected.

SQL>

Adding the XML keyword to the PIVOT operator allows us to convert the generated pivot results to XML format. It also makes the PIVOT a little more flexible, allowing us to replace the hard coded IN clause with a subquery, or the ANY wildcard.

SET LONG 10000

SELECT *

FROM   (SELECT product_code, quantity

FROM   pivot_test)

PIVOT XML (SUM(quantity) AS sum_quantity FOR (product_code) IN (SELECT DISTINCT product_code

FROM   pivot_test

WHERE  id < 10));

product_code_XML

----------------------------------------------------------------------------------------------------

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">210</column></

item><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">90</column></item><

item><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">160</column></item><item>

<column name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY">90</column></item></PivotSet>

1 row selected.

SQL>

SELECT *

FROM   (SELECT product_code, quantity

FROM   pivot_test)

PIVOT XML (SUM(quantity) AS sum_quantity FOR (product_code) IN (ANY));

product_code_XML

----------------------------------------------------------------------------------------------------

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">210</column></

item><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">90</column></item><

item><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">160</column></item><item>

<column name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY">90</column></item></PivotSet>

1 row selected.

SQL>

Once again, the results can be broken down by customer, with each customers XML presented as a separate row.

SET LONG 10000

SELECT *

FROM   (SELECT customer_id, product_code, quantity

FROM   pivot_test)

PIVOT XML (SUM(quantity) AS sum_quantity FOR (product_code) IN (SELECT DISTINCT product_code

FROM   pivot_test));

CUSTOMER_ID

-----------

PRODUCT_CODE_XML

----------------------------------------------------------------------------------------------------

1

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">10</column></i

tem><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">20</column></item><i

tem><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">30</column></item><item><c

olumn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY"></column></item></PivotSet>

2

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">40</column></i

tem><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY"></column></item><ite

CUSTOMER_ID

-----------

PRODUCT_CODE_XML

----------------------------------------------------------------------------------------------------

m><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">50</column></item><item><col

umn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY"></column></item></PivotSet>

3

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">60</column></i

tem><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY">70</column></item><i

tem><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY">80</column></item><item><c

olumn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY">90</column></item></PivotSet>

CUSTOMER_ID

-----------

PRODUCT_CODE_XML

----------------------------------------------------------------------------------------------------

4

<PivotSet><item><column name = "PRODUCT_CODE">A</column><column name = "SUM_QUANTITY">100</column></

item><item><column name = "PRODUCT_CODE">B</column><column name = "SUM_QUANTITY"></column></item><it

em><column name = "PRODUCT_CODE">C</column><column name = "SUM_QUANTITY"></column></item><item><colu

mn name = "PRODUCT_CODE">D</column><column name = "SUM_QUANTITY"></column></item></PivotSet>

4 rows selected.

SQL>

UNPIVOT

The UNPIVOT operator converts column-based data into separate rows. To see the UNPIVOT operator in action we need to create a test table.

CREATE TABLE unpivot_test (

id              NUMBER,

customer_id     NUMBER,

product_code_a  NUMBER,

product_code_b  NUMBER,

product_code_c  NUMBER,

product_code_d  NUMBER

);

INSERT INTO unpivot_test VALUES (1, 101, 10, 20, 30, NULL);

INSERT INTO unpivot_test VALUES (2, 102, 40, NULL, 50, NULL);

INSERT INTO unpivot_test VALUES (3, 103, 60, 70, 80, 90);

INSERT INTO unpivot_test VALUES (4, 104, 100, NULL, NULL, NULL);

COMMIT;

So our test data starts off looking like this.

SELECT * FROM unpivot_test;

ID CUSTOMER_ID PRODUCT_CODE_A PRODUCT_CODE_B PRODUCT_CODE_C PRODUCT_CODE_D

---------- ----------- -------------- -------------- -------------- --------------

1         101             10             20             30

2         102             40                            50

3         103             60             70             80             90

4         104            100

4 rows selected.

SQL>

The UNPIVOT operator converts this column-based data into individual rows.

SELECT *

FROM   unpivot_test

UNPIVOT (quantity FOR product_code IN (product_code_a AS 'A', product_code_b AS 'B', product_code_c AS 'C', product_code_d AS 'D'));

ID CUSTOMER_ID P   QUANTITY

---------- ----------- - ----------

1         101 A         10

1         101 B         20

1         101 C         30

2         102 A         40

2         102 C         50

3         103 A         60

3         103 B         70

3         103 C         80

3         103 D         90

4         104 A        100

10 rows selected.

SQL>

There are several things to note about the query:

  • The required column names, in this case QUANTITY and PRODUCT_CODE, are define in the UNPIVOT clause. These can be set to any name not currently in the driving table.
  • The columns to be unpivoted must be named in the IN clause.
  • The PRODUCT_CODE value will match the column name it is derived from, unless you alias it to another value.
  • By default the EXCLUDE NULLS clause is used. To override the default behaviour use the INCLUDE NULLS clause.

The following query shows the inclusion of the INCLUDE NULLS clause.

SELECT *

FROM   unpivot_test

UNPIVOT INCLUDE NULLS (quantity FOR product_code IN (product_code_a AS 'A', product_code_b AS 'B', product_code_c AS 'C', product_code_d AS 'D'));

ID CUSTOMER_ID P   QUANTITY

---------- ----------- - ----------

1         101 A         10

1         101 B         20

1         101 C         30

1         101 D

2         102 A         40

2         102 B

2         102 C         50

2         102 D

3         103 A         60

3         103 B         70

3         103 C         80

ID CUSTOMER_ID P   QUANTITY

---------- ----------- - ----------

3         103 D         90

4         104 A        100

4         104 B

4         104 C

4         104 D

16 rows selected.

SQL>

Prior to 11g, we can get the same result using the DECODE function and a pivot table with the correct number of rows. In the following example we use the CONNECT BY clause in a query from dual to generate the correct number of rows for the unpivot operation.

SELECT id,

customer_id,

DECODE(unpivot_row, 1, 'A',

2, 'B',

3, 'C',

4, 'D',

'N/A') AS product_code,

DECODE(unpivot_row, 1, product_code_a,

2, product_code_b,

3, product_code_c,

4, product_code_d,

'N/A') AS quantity

FROM   unpivot_test,

(SELECT level AS unpivot_row FROM dual CONNECT BY level <= 4)

ORDER BY 1,2,3;

ID CUSTOMER_ID PRO   QUANTITY

---------- ----------- --- ----------

1         101 A           10

1         101 B           20

1         101 C           30

1         101 D

2         102 A           40

2         102 B

2         102 C           50

2         102 D

3         103 A           60

3         103 B           70

3         103 C           80

ID CUSTOMER_ID PRO   QUANTITY

---------- ----------- --- ----------

3         103 D           90

4         104 A          100

4         104 B

4         104 C

4         104 D

16 rows selected.

SQL>

Oracle11g 行列转换函数PIVOT and UNPIVOT的更多相关文章

  1. Oracle 行列转换函数pivot、unpivot的使用(二)

    一.行转列pivot 关键函数pivot,其用法如下 pivot(聚合函数 for 列名 in(类型)) select * from table_name pivot(max(column_name) ...

  2. SQL(横表和纵表)行列转换,PIVOT与UNPIVOT的区别和使用方法举例,合并列的例子

    使用过SQL Server 2000的人都知道,要想实现行列转换,必须综合利用聚合函数和动态SQL,具体实现起来需要一定的技巧,而在SQL Server 2005中,使用新引进的关键字PIVOT/UN ...

  3. 行列转换小结 Pivot ,Unpivot (转,改)

    行专列 Pivot 1)SQL 2000版本 静态 SELECT ID , SUM(CASE Code WHEN 'Item1' THEN Value END) AS Item1 , SUM(CASE ...

  4. [转]Oracle SQL函数pivot、unpivot转置函数实现行转列、列转行

    原文地址:http://blog.csdn.net/seandba/article/details/72730657 函数PIVOT.UNPIVOT转置函数实现行转列.列转行,效果如下图所示: 1.P ...

  5. oracle行列转换函数的使用

    oracle 10g wmsys.wm_concat行列转换函数的使用: 首先让我们来看看这个神奇的函数wm_concat(列名),该函数可以把列值以","号分隔起来,并显示成一行 ...

  6. KingbaseES 行列转换函数

    关键字:    行专列,列转行, pivot, unpivot 行列转换是在数据分析中经常用到的一项功能,KingbaseES从V8R6C3B0071版本开始通过扩展插件(kdb_utils_func ...

  7. oracle 行列转换函数之WM_CONCAT和LISTAGG的使用(一)

    一.wm_concat函数 wm_concat能够实现同样的功能,但是有时在11g中使用需要用to_char()进行转换,否则会出现不兼容现象(WMSYS.WM_CONCAT: 依赖WMSYS 用户, ...

  8. oracle 行转列函数pivot和unpivot

    今天接到业务部门的一个需求,需要对同一公司的不同财务指标进行排序,需要用到oracle的行转列函数unpivot. 财务报表的表结构为: 要实现业务部门的排序筛选功能,需要首先将行数据转为列数据: 使 ...

  9. SQL SERVER 合并重复行,行列转换

    引用自:http://www.cnblogs.com/love-summer/archive/2012/03/27/2419778.html sql server2000 里面如何实现oracle10 ...

随机推荐

  1. WinAPI: WinExec - 运行外部程序

    原文:http://www.cnblogs.com/del/archive/2008/02/13/1067871.html //声明 WinExec(   lpCmdLine: LPCSTR; {文件 ...

  2. Linked List Cycle 判断一个链表是否存在回路(循环)

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...

  3. Grunt入门学习之(2) -- Gruntfile的编写

    Gruntfile由以下几部分构成: "wrapper" 函数 项目与任务,目标配置 加载grunt插件和任务 自定义任务 1.wrapper函数(包装函数) 每一个 Gruntf ...

  4. thinkPHP -01- thinkPHP5.0 安装与测试

    thinkPHP -01- thinkPHP5.0 安装与测试 1.thinkPHP 5 官网下载地址:http://www.thinkphp.cn/down.html 2.打开 Wampserver ...

  5. vuejs plus d3

    vuejs 是一个数据驱动视图的前端框架,一切皆可以作为可重用的组件加以使用. d3则是数据可视化javascript库,如何将二者的长处相结合是一个挑战. https://tyronetudehop ...

  6. 连接到 Azure 上的 SQL Server 虚拟机(经典部署)

    概述 本主题介绍如何连接到运行于 Azure 虚拟机的 SQL Server 实例. 它介绍了一些常规连接方案,并提供了在 Azure VM 中配置 SQL Server 连接的详细步骤. Impor ...

  7. CentOS随笔 - 2.CentOS7安装ftp支持(vsftpd)

    前言 转帖请注明出处: http://www.cnblogs.com/Troy-Lv5/ 在前一篇文章中介绍了在虚拟机中安装CentOS7, 接下来就要进行配置了, 第一个就是安装ftp支持. 要不然 ...

  8. 让UpdatePanel支持文件上传(2):服务器端组件 .

    我们现在来关注服务器端的组件.目前的主要问题是,我们如何让页面(事实上是ScriptManager控件)认为它接收到的是一个异步的回送?ScriptManager控件会在HTTP请求的Header中查 ...

  9. 【转】snmpwalk常用用法

    在日常监控中,经常会用到snmp服务,而snmpwalk命令则是测试系统各种信息最有效的方法,现总结一些常用的方法如下: 1.snmpwalk -v 2c -c public 10.103.33.1 ...

  10. HTTP协议图--HTTP 响应状态码(重点分析)

    1. 状态码概述 HTTP 状态码负责表示客户端 HTTP 请求的返回结果.标记服务器端的处理是否正常.通知出现的错误等工作. HTTP 状态码如 200 OK ,以 3 位数字和原因短语组成.数字中 ...