设为首页 收藏本站
查看: 1695|回复: 0

[经验分享] Oracle 行转列,列转行

[复制链接]

尚未签到

发表于 2016-7-28 09:55:08 | 显示全部楼层 |阅读模式
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

 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-250529-1-1.html 上篇帖子: (原)Oracle 获取每周的起始日期 下篇帖子: 所获,不止Oracle之索引篇(1)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表