Oracle SQL Dynamic PIVOT 当前月份、过去 6 个月和总计
Oracle SQL Dynamic PIVOT Current month, last 6 Months and a total
我有一个简单的查询 returns 我的基础数据:
SELECT b.MRID, r.GID, b.VDATE
FROM BAC b
LEFT JOIN BAR r ON b.MRID = r.RID
输出:
MRID GID VDATE
John Smith com 15-Oct-18
John Smith com NULL
Joe Bloggs ad 02-Jun-18
Joe Bloggs ad 14-Jul-18
Homer Simpson bil 17-Oct-18
Homer Simpson bil NULL
Rick Grimes zee 12-Nov-18
Rick Grimes zee NULL
我要输出的是动态 PIVOT:
MRID GID Current Month Oct-18 Sep-18 Aug-18 Jul-18 Jun-18 May-18 Total
John Smith com 0 1 0 0 0 0 0 1
Joe Bloggs ad 0 0 0 0 1 1 0 2
Homer Simpson bil 0 1 0 0 0 0 0 1
Rick Grimes zee 1 0 0 0 0 0 0 1
我希望它随着当前月份和总数的变化而动态变化。
动态更改列名称将很困难。有几个解决方案,但其中 none 确实是您想要的
1) 执行 "pivot XML" 并在要转换为 ON 的值列表中指定 ANY。但它会给你一个 XML 的结果,这是......不理想
2) 执行 PIPELINED 函数接受游标,这将为您创建枢轴。但它需要创建类型和存储过程
如果您同意将您的列名称更改为像 MONTH-1 这样的通用名称...您可以按以下方式轻松完成:
CREATE TABLE BAC ( MRID VARCHAR2(30), VDATE DATE );
CREATE TABLE BAR ( RID VARCHAR2(30), GID VARCHAR2(3));
INSERT INTO BAC VALUES ( 'John Smith',TO_DATE('15-Oct-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'John Smith',null);
INSERT INTO BAC VALUES ( 'Joe Bloggs',TO_DATE('02-Jun-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Joe Bloggs',TO_DATE('14-Jul-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Homer Simpson',TO_DATE('17-Oct-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Homer Simpson',null);
INSERT INTO BAC VALUES ( 'Rick Grimes',TO_DATE('12-Nov-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Rick Grimes',null);
INSERT INTO BAR VALUES ( 'John Smith','com');
INSERT INTO BAR VALUES ( 'Joe Bloggs','ad');
INSERT INTO BAR VALUES ( 'Homer Simpson','bil');
INSERT INTO BAR VALUES ( 'Rick Grimes','zee');
WITH MONTHS AS
(
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MONTH'),-LEVEL+1) AS MONTH, DECODE(LEVEL,1,'CURRENT_MONTH','MONTH_MINUS_'||(LEVEL-1)) AS MONTH_NAME FROM DUAL CONNECT BY LEVEL <=7
)
SELECT
MRID,
GID,
NVL(CURRENT_MONTH,0) AS CURRENT_MONTH,
NVL(MONTH_MINUS_1,0) AS MONTH_MINUS_1,
NVL(MONTH_MINUS_2,0) AS MONTH_MINUS_2,
NVL(MONTH_MINUS_3,0) AS MONTH_MINUS_3,
NVL(MONTH_MINUS_4,0) AS MONTH_MINUS_4,
NVL(MONTH_MINUS_5,0) AS MONTH_MINUS_5,
NVL(MONTH_MINUS_6,0) AS MONTH_MINUS_6,
TOTAL
FROM (
SELECT
DISTINCT B.MRID, R.GID, MONTH_NAME,
COUNT(*) OVER (PARTITION BY B.MRID, R.GID, TRUNC(VDATE,'MONTH') ORDER BY VDATE ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS CNT,
COUNT(*) OVER (PARTITION BY B.MRID, R.GID ORDER BY VDATE ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS TOTAL
FROM MONTHS M
JOIN BAC B ON M.MONTH=TRUNC(B.VDATE,'MONTH')
LEFT JOIN BAR R ON b.MRID = r.RID
) PIVOT
( SUM(CNT)
FOR MONTH_NAME IN
('CURRENT_MONTH' AS CURRENT_MONTH ,
'MONTH_MINUS_1' AS MONTH_MINUS_1,
'MONTH_MINUS_2' AS MONTH_MINUS_2,
'MONTH_MINUS_3' AS MONTH_MINUS_3,
'MONTH_MINUS_4' AS MONTH_MINUS_4,
'MONTH_MINUS_5' AS MONTH_MINUS_5,
'MONTH_MINUS_6' AS MONTH_MINUS_6)
);
MRID GID CURRENT_MONTH MONTH_MINUS_1 MONTH_MINUS_2 MONTH_MINUS_3 MONTH_MINUS_4 MONTH_MINUS_5 MONTH_MINUS_6 TOTAL
------------------------------ --- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ----------
John Smith com 0 1 0 0 0 0 0 1
Rick Grimes zee 1 0 0 0 0 0 0 1
Homer Simpson bil 0 1 0 0 0 0 0 1
Joe Bloggs ad 0 0 0 0 1 1 0 2
我有一个简单的查询 returns 我的基础数据:
SELECT b.MRID, r.GID, b.VDATE
FROM BAC b
LEFT JOIN BAR r ON b.MRID = r.RID
输出:
MRID GID VDATE
John Smith com 15-Oct-18
John Smith com NULL
Joe Bloggs ad 02-Jun-18
Joe Bloggs ad 14-Jul-18
Homer Simpson bil 17-Oct-18
Homer Simpson bil NULL
Rick Grimes zee 12-Nov-18
Rick Grimes zee NULL
我要输出的是动态 PIVOT:
MRID GID Current Month Oct-18 Sep-18 Aug-18 Jul-18 Jun-18 May-18 Total
John Smith com 0 1 0 0 0 0 0 1
Joe Bloggs ad 0 0 0 0 1 1 0 2
Homer Simpson bil 0 1 0 0 0 0 0 1
Rick Grimes zee 1 0 0 0 0 0 0 1
我希望它随着当前月份和总数的变化而动态变化。
动态更改列名称将很困难。有几个解决方案,但其中 none 确实是您想要的
1) 执行 "pivot XML" 并在要转换为 ON 的值列表中指定 ANY。但它会给你一个 XML 的结果,这是......不理想
2) 执行 PIPELINED 函数接受游标,这将为您创建枢轴。但它需要创建类型和存储过程
如果您同意将您的列名称更改为像 MONTH-1 这样的通用名称...您可以按以下方式轻松完成:
CREATE TABLE BAC ( MRID VARCHAR2(30), VDATE DATE );
CREATE TABLE BAR ( RID VARCHAR2(30), GID VARCHAR2(3));
INSERT INTO BAC VALUES ( 'John Smith',TO_DATE('15-Oct-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'John Smith',null);
INSERT INTO BAC VALUES ( 'Joe Bloggs',TO_DATE('02-Jun-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Joe Bloggs',TO_DATE('14-Jul-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Homer Simpson',TO_DATE('17-Oct-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Homer Simpson',null);
INSERT INTO BAC VALUES ( 'Rick Grimes',TO_DATE('12-Nov-18','DD-MON-YY'));
INSERT INTO BAC VALUES ( 'Rick Grimes',null);
INSERT INTO BAR VALUES ( 'John Smith','com');
INSERT INTO BAR VALUES ( 'Joe Bloggs','ad');
INSERT INTO BAR VALUES ( 'Homer Simpson','bil');
INSERT INTO BAR VALUES ( 'Rick Grimes','zee');
WITH MONTHS AS
(
SELECT ADD_MONTHS(TRUNC(SYSDATE,'MONTH'),-LEVEL+1) AS MONTH, DECODE(LEVEL,1,'CURRENT_MONTH','MONTH_MINUS_'||(LEVEL-1)) AS MONTH_NAME FROM DUAL CONNECT BY LEVEL <=7
)
SELECT
MRID,
GID,
NVL(CURRENT_MONTH,0) AS CURRENT_MONTH,
NVL(MONTH_MINUS_1,0) AS MONTH_MINUS_1,
NVL(MONTH_MINUS_2,0) AS MONTH_MINUS_2,
NVL(MONTH_MINUS_3,0) AS MONTH_MINUS_3,
NVL(MONTH_MINUS_4,0) AS MONTH_MINUS_4,
NVL(MONTH_MINUS_5,0) AS MONTH_MINUS_5,
NVL(MONTH_MINUS_6,0) AS MONTH_MINUS_6,
TOTAL
FROM (
SELECT
DISTINCT B.MRID, R.GID, MONTH_NAME,
COUNT(*) OVER (PARTITION BY B.MRID, R.GID, TRUNC(VDATE,'MONTH') ORDER BY VDATE ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS CNT,
COUNT(*) OVER (PARTITION BY B.MRID, R.GID ORDER BY VDATE ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS TOTAL
FROM MONTHS M
JOIN BAC B ON M.MONTH=TRUNC(B.VDATE,'MONTH')
LEFT JOIN BAR R ON b.MRID = r.RID
) PIVOT
( SUM(CNT)
FOR MONTH_NAME IN
('CURRENT_MONTH' AS CURRENT_MONTH ,
'MONTH_MINUS_1' AS MONTH_MINUS_1,
'MONTH_MINUS_2' AS MONTH_MINUS_2,
'MONTH_MINUS_3' AS MONTH_MINUS_3,
'MONTH_MINUS_4' AS MONTH_MINUS_4,
'MONTH_MINUS_5' AS MONTH_MINUS_5,
'MONTH_MINUS_6' AS MONTH_MINUS_6)
);
MRID GID CURRENT_MONTH MONTH_MINUS_1 MONTH_MINUS_2 MONTH_MINUS_3 MONTH_MINUS_4 MONTH_MINUS_5 MONTH_MINUS_6 TOTAL
------------------------------ --- ------------- ------------- ------------- ------------- ------------- ------------- ------------- ----------
John Smith com 0 1 0 0 0 0 0 1
Rick Grimes zee 1 0 0 0 0 0 0 1
Homer Simpson bil 0 1 0 0 0 0 0 1
Joe Bloggs ad 0 0 0 0 1 1 0 2