Oracle 行转列,列转行

Oracle Pivot/Unpivot

此特性只适用于Oracle 11g 以上版本

CREATE TABLE CUSTOMERS
(
CUST_ID NUMBER(10),
CUST_NAME VARCHAR2(20),
STATE_CODE VARCHAR2(2),
TIMES_PURCHASED NUMBER(3)
);

INSERT INTO CUSTOMERS VALUES(1,'ANKER','CT',1);
INSERT INTO CUSTOMERS VALUES(1,'ANKER','ET',2);
INSERT INTO CUSTOMERS VALUES(1,'ANKER','DT',3);
INSERT INTO CUSTOMERS VALUES(1,'ANKER','QD',4);
INSERT INTO CUSTOMERS VALUES(2,'JONH','ET',2);
INSERT INTO CUSTOMERS VALUES(2,'JONH','DT',3);
INSERT INTO CUSTOMERS VALUES(2,'JONH','QD',2);
INSERT INTO CUSTOMERS VALUES(3,'QIANG','DT',3);
INSERT INTO CUSTOMERS VALUES(3,'QIANG','QD',4);
COMMIT;

--该记录显示了客户所在的州以及该客户在商店购物的次数。当该客户从商店购买更多物品时,列 times_purchased 会进行更新。 

SQL> SELECT * FROM CUSTOMERS;

   CUST_ID CUST_NAME            ST TIMES_PURCHASED
---------- -------------------- -- ---------------
         1 Anker                CT               1
         1 Anker                ET               2
         1 Anker                DT               3
         1 Anker                QD               4
         2 Jonh                 ET               2
         2 Jonh                 DT               3
         2 Jonh                 QD               2
         3 Qiang                DT               3
         3 Qiang                QD               4

已选择9行。


PIVOT用法
--1.查看每个州,每个客户的购买频率
SELECT * FROM CUSTOMERS 
PIVOT(
SUM(TIMES_PURCHASED) FOR STATE_CODE IN ('QD' AS "New York", 'CT' AS "Connecticut", 'ET' AS "New Jersey", 'DT' AS "Missouri")
);

--从结果可以看出,pivot将针对非pivot涉及的字段进行group by,pivot中的 in (...)子句中的值将作为列,聚合的值将作为列的值

   CUST_ID CUST_NAME              New York Connecticut New Jersey   Missouri
---------- -------------------- ---------- ----------- ---------- ----------
         1 Anker                         4           1          2          3
         2 Jonh                          2                      2          3
         3 Qiang                         4                                 3

--2.了解各个州的购买频率,即,各个州有多少客户只购物一次、两次、三次等等。如果使用常规 SQL
SQL> SELECT STATE_CODE, TIMES_PURCHASED, COUNT(*)
  2    FROM CUSTOMERS
  3   GROUP BY STATE_CODE, TIMES_PURCHASED;

ST TIMES_PURCHASED   COUNT(*)
-- --------------- ----------
QD               4          2
QD               2          1
CT               1          1
ET               2          2
DT               3          3

--这样看起来不太直观
SELECT *
FROM 
(
SELECT TIMES_PURCHASED, STATE_CODE FROM CUSTOMERS) T 
PIVOT(
COUNT(STATE_CODE) FOR STATE_CODE IN ('QD', 'CT', 'ET', 'DT')
)

TIMES_PURCHASED       'QD'       'CT'       'ET'       'DT'
--------------- ---------- ---------- ---------- ----------
              1          0          1          0          0
              2          1          0          2          0
              4          2          0          0          0
              3          0          0          0          3
--但是假设您希望显示州名而非缩写
SELECT *
FROM 
(
  SELECT TIMES_PURCHASED as "Puchase Frequency", STATE_CODE FROM CUSTOMERS) T 
  PIVOT(COUNT(STATE_CODE) as CNT
  FOR STATE_CODE IN ('QD' AS "New York", 'CT' AS "Connecticut", 'ET' AS "New Jersey", 'DT' AS "Missouri")
);

Puchase Frequency New York_CNT Connecticut_CNT New Jersey_CNT Missouri_CNT
----------------- ------------ --------------- -------------- ------------
                1            0               1              0            0
                2            1               0              2            0
                4            2               0              0            0
                3            0               0              0            3
-----------------------------------------------------------------------------------------------------------------------------------
Unpivot 讲解

--1.将上面的pivot后的结果进行反转回来
CREATE TABLE TAB_MATRIX1
AS
SELECT * FROM CUSTOMERS 
PIVOT(
SUM(TIMES_PURCHASED) FOR STATE_CODE IN ('QD' AS "NEW YORK", 'CT' AS "CONNECTICUT", 'ET' AS "NEW JERSEY", 'DT' AS "MISSOURI")
);

--查询表
SQL> SELECT * FROM TAB_MATRIX1
  2  ;

   CUST_ID CUST_NAME              New York Connecticut New Jersey   Missouri
---------- -------------------- ---------- ----------- ---------- ----------
         1 Anker                         4           1          2          3
         2 Jonh                          2                      2          3
         3 Qiang                         4                                 3
--从结果中可以看出,for .. in (..)中的列名将作为state_code列的值,字段state_counts中的列将由原来的列值来代替
SQL> SELECT * FROM TAB_MATRIX1
  2  unpivot
  3  (
  4  state_counts
  5  for state_code in ("New York","Connecticut","New Jersey","Missouri")
  6  );

   CUST_ID CUST_NAME            STATE_CODE  STATE_COUNTS
---------- -------------------- ----------- ------------
         1 Anker                New York               4
         1 Anker                Connecticut            1
         1 Anker                New Jersey             2
         1 Anker                Missouri               3
         2 Jonh                 New York               2
         2 Jonh                 New Jersey             2
         2 Jonh                 Missouri               3
         3 Qiang                New York               4
         3 Qiang                Missouri               3

已选择9行。

--将上面第二个结果也进行反转
CREATE TABLE TAB_MATRIX2 AS 
SELECT *
FROM 
(
  SELECT TIMES_PURCHASED as "Puchase Frequency", STATE_CODE FROM CUSTOMERS) T 
  PIVOT(COUNT(STATE_CODE) as CNT
  FOR STATE_CODE IN ('QD' AS "New York", 'CT' AS "Connecticut", 'ET' AS "New Jersey", 'DT' AS "Missouri")
);

SQL> SELECT * FROM TAB_MATRIX2;

Puchase Frequency New York_CNT Connecticut_CNT New Jersey_CNT Missouri_CNT
----------------- ------------ --------------- -------------- ------------
                1            0               1              0            0
                2            1               0              2            0
                4            2               0              0            0
                3            0               0              0            3

SELECT  * FROM TAB_MATRIX2
UNPIVOT
(
CNT_STATE_CODE
FOR STATE_CODE IN ("New York_CNT","Connecticut_CNT","New Jersey_CNT","Missouri_CNT")
);

Puchase Frequency STATE_CODE      CNT_STATE_CODE
----------------- --------------- --------------
                1 New York_CNT                 0
                1 Connecticut_CNT              1
                1 New Jersey_CNT               0
                1 Missouri_CNT                 0
                2 New York_CNT                 1
                2 Connecticut_CNT              0
                2 New Jersey_CNT               2
                2 Missouri_CNT                 0
                4 New York_CNT                 2
                4 Connecticut_CNT              0
                4 New Jersey_CNT               0
                4 Missouri_CNT                 0
                3 New York_CNT                 0
                3 Connecticut_CNT              0
                3 New Jersey_CNT               0
                3 Missouri_CNT                 3
---------------------------------------------------------------------------------------------------------------------
Oracle 11g之前的版本如何实现行转列及列转行

CREATE TABLE T 
AS
SELECT * FROM
(
SELECT OWNER,OBJECT_TYPE,COUNT(*) AS CNT FROM DBA_OBJECTS 
GROUP BY OWNER,OBJECT_TYPE
) WHERE ROWNUM <= 3;

admin@ORCL> SELECT * FROM T;

OWNER                          OBJECT_TYPE                CNT
------------------------------ ------------------- ----------
BI                             SYNONYM                      8
HR                             VIEW                         1
HR                             INDEX                       19
--列转行
admin@ORCL> SELECT OWNER,
  2         SUM(CASE
  3               WHEN OBJECT_TYPE = 'SYNONYM' THEN
  4                CNT
  5               ELSE
  6                0
  7             END) AS TYPE_SYNONYM,
  8         SUM(CASE
  9               WHEN OBJECT_TYPE = 'VIEW' THEN
 10                CNT
 11               ELSE
 12                0
 13             END) AS TYPE_VIEW,
 14         SUM(CASE
 15               WHEN OBJECT_TYPE = 'INDEX' THEN
 16                CNT
 17               ELSE
 18                0
 19             END)  AS TYPE_INDEX
 20    FROM T
 21   GROUP BY OWNER;

OWNER                          TYPE_SYNONYM  TYPE_VIEW TYPE_INDEX
------------------------------ ------------ ---------- ----------
HR                                        0          1         19
BI                                        8          0          0


--列转行
DROP TABLE T PURGE;

CREATE TABLE T 
(
OWNER VARCHAR2(10),
TYPE_SYNONYM INT,
TYPE_VIEW INT,
TYPE_INDEX INT
);

INSERT INTO T VALUES('HR','0','1','19');
INSERT INTO T VALUES('BI','8','0','0');

COMMIT;
--查看数据
admin@ORCL> SELECT * FROM T;
OWNER      TYPE_SYNONYM  TYPE_VIEW TYPE_INDEX
---------- ------------ ---------- ----------
HR                    0          1         19
BI                    8          0          0

--列转行

admin@ORCL> SELECT OWNER, 'SYNONYM' AS TYPE, TYPE_SYNONYM
  2    FROM T
  3  UNION ALL
  4  SELECT OWNER, 'VIEW', TYPE_VIEW
  5    FROM T
  6  UNION ALL
  7  SELECT OWNER, 'INDEX', TYPE_INDEX FROM T;

OWNER      TYPE    TYPE_SYNONYM
---------- ------- ------------
HR         SYNONYM            0
BI         SYNONYM            8
HR         VIEW               1
BI         VIEW               0
HR         INDEX             19
BI         INDEX              0
 

猜你喜欢

转载自yangeoo.iteye.com/blog/1917584