Oracle:PIVOT and UNPIVOT Operators in Oracle Database 11g Release 1
2011-08-24 10:25
751 查看
This article shows how to use the new
PIVOT
UNPIVOT
So our test data starts off looking like this.
In its basic form the
If we want to break it down by customer, we simply include the
Prior to 11g we could accomplish a similar result using the
Adding the
Once again, the results can be broken down by customer, with each customers XML presented as a separate row.
So our test data starts off looking like this.
The
There are several things to note about the query:
The required column names, in this case
The columns to be unpivoted must be named in the
The
By default the
The following query shows the inclusion of the
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.
For more information see:
PIVOT
UNPIVOT
Hope this helps. Regards Tim...
PIVOTand
UNPIVOToperators in 11g, as well as giving a pre-11g solution to the same problems.
PIVOT
UNPIVOT
PIVOT
ThePIVOToperator takes data in separate rows, aggregates it and converts it into columns. To see the
PIVOToperator 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
PIVOToperator is quite limited. We are forced to list the required values to
PIVOTusing 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_IDcolumn 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
DECODEfunction 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
XMLkeyword to the
PIVOToperator allows us to convert the generated pivot results to XML format. It also makes the
PIVOTa 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
TheUNPIVOToperator converts column-based data into separate rows. To see the
UNPIVOToperator 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
UNPIVOToperator 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
QUANTITYand
PRODUCT_CODE, are define in the
UNPIVOTclause. These can be set to any name not currently in the driving table.
The columns to be unpivoted must be named in the
INclause.
The
PRODUCT_CODEvalue will match the column name it is derived from, unless you alias it to another value.
By default the
EXCLUDE NULLSclause is used. To override the default behaviour use the
INCLUDE NULLSclause.
The following query shows the inclusion of the
INCLUDE NULLSclause.
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>
For more information see:
PIVOT
UNPIVOT
Hope this helps. Regards Tim...
相关文章推荐
- 转载:Data Guard Physical Standby Setup in Oracle Database 11g Release 2
- Data Guard Physical Standby Setup in Oracle Database 11g Release 2
- DDL With the WAIT Option (DDL_LOCK_TIMEOUT) in Oracle Database 11g Release 1
- pivot and unpivot queries in 11g
- Using Oracle Database 11g Release 2 Result Cache in an Oracle RAC Environment
- 用户、补丁-Create Oracle ASM Cluster File Systems (ACFS) in Oracle Database 11g Release 2-by小雨
- Adaptive Cursor Sharing in Oracle Database 11g Release 1
- (转)Fine-Grained Access to Network Services in Oracle Database 11g Release 1
- Oracle® Database Performance Tuning Guide 11g Release 2 (11.2)----Configuring and Using Memory
- Oracle:Virtual Columns in Oracle Database 11g Release 1
- pivot and unpivot queries in 11g
- Online Table Redefinition Enhancements in Oracle Database 11g Release 1
- Data Guard Physical Standby Setup in Oracle Database 11g Release 2
- Partitioning Enhancements in Oracle Database 11g Release 1
- Table Compression Enhancements in Oracle Database 11g Release 1
- Data Guard Physical Standby Setup in Oracle Database 11g Release 2
- pivot and unpivot queries in 11g
- Adaptive Cursor Sharing in Oracle Database 11g Release 1
- DNS Configuration for the SCAN used with Oracle RAC Database 11g Release 2
- 《Oracle Database Concepts 11g Release 2》读书笔记(1)-schema