多列,多表列到行 unpivot

Posted

技术标签:

【中文标题】多列,多表列到行 unpivot【英文标题】:Multiple columns, multiple table columns to rows unpivot 【发布时间】:2017-01-21 06:09:52 【问题描述】:

这是我正在使用的表的 ddl。

CREATE TABLE "BISAMPLE"."SUMLEDGER" 
   (    "FUND" VARCHAR2(6 BYTE), 
    "ORG" VARCHAR2(6 BYTE), 
    "ACCT" VARCHAR2(6 BYTE), 
    "PROG" VARCHAR2(6 BYTE), 
    "YEAR" NUMBER, 
    "S01_BUDGET" NUMBER, 
    "S01_BUDGET_ADJ" NUMBER, 
    "S01_YTD_ACTV" NUMBER, 
    "S01_ENCUMB" NUMBER, 
    "S02_BUDGET" NUMBER, 
    "S02_BUDGET_ADJ" NUMBER, 
    "S02_YTD_ACTV" NUMBER, 
    "S02_ENCUMB" NUMBER
   )

这里是示例数据的插入。

REM INSERTING into SUMLEDGER
SET DEFINE OFF;
Insert into SUMLEDGER (FUND,ORG,ACCT,PROG,YEAR,S01_BUDGET,S01_BUDGET_ADJ,S01_YTD_ACTV,S01_ENCUMB,S02_BUDGET,S02_BUDGET_ADJ,S02_YTD_ACTV,S02_ENCUMB) values ('100001','3999','3220','06',6,20,30,15,15,10,20,10,40);
Insert into SUMLEDGER (FUND,ORG,ACCT,PROG,YEAR,S01_BUDGET,S01_BUDGET_ADJ,S01_YTD_ACTV,S01_ENCUMB,S02_BUDGET,S02_BUDGET_ADJ,S02_YTD_ACTV,S02_ENCUMB) values ('100001','3999','3220','06',7,20,30,15,15,10,20,30,40);
Insert into SUMLEDGER (FUND,ORG,ACCT,PROG,YEAR,S01_BUDGET,S01_BUDGET_ADJ,S01_YTD_ACTV,S01_ENCUMB,S02_BUDGET,S02_BUDGET_ADJ,S02_YTD_ACTV,S02_ENCUMB) values ('100001','3999','3460','06',6,25,30,20,20,20,20,30,40);
Insert into SUMLEDGER (FUND,ORG,ACCT,PROG,YEAR,S01_BUDGET,S01_BUDGET_ADJ,S01_YTD_ACTV,S01_ENCUMB,S02_BUDGET,S02_BUDGET_ADJ,S02_YTD_ACTV,S02_ENCUMB) values ('100001','3999','3220','06',8,20,35,25,30,30,22,15,30);

这是将在此查询中使用的第二个表。

CREATE TABLE "BISAMPLE"."FUNDING" 
   (    "FUNDING_START_DATE" DATE, 
    "FUNDING_NUMBER" VARCHAR2(6 BYTE)
   )

这是表格插入。

REM INSERTING into FUNDING
SET DEFINE OFF;
Insert into FUNDING (FUNDING_START_DATE,FUNDING_NUMBER) values (to_date('21-JAN-2017 03:47:42','DD-MON-RRRR HH24:MI:SS'),'100001');

我正在尝试使用 unpivot 函数将我的列转换为行。但我目前非常不成功。但是,我可以使用以下查询来完成相同的输出。

SELECT 
 FUND,
  ORG,
  ACCT,
  PROG,
  YEAR,
  SUM(S01_BUDGET + S01_BUDGET_ADJ) BUDG,
   S01_YTD_ACTV YEAR_TO_DATE,
   S01_ENCUMB ENCUMBRANCE,
  '01' AS SPERIOD,
  CASE
        --PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN '01' --JAN PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN '02' --FEB
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN '03' --MAR
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN '04'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN '05'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN '06'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN '07'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN '08' --AUG
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN '09'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN '10' --OCT
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'NOV'
      THEN '11'
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'DEC'
      THEN '12'
      ELSE '00'
    END AS SMONTH,

  (CASE
        --PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'NOV'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'DEC'
      THEN TO_NUMBER(YEAR)
      ELSE TO_NUMBER(YEAR)
    END) AS S_YEAR
FROM  SUMLEDGER ,
      FUNDING
WHERE FUNDING_NUMBER =  FUND
group by 
FUND,
  ORG,
  ACCT,
  PROG,
  YEAR,
   S01_YTD_ACTV ,
   S01_ENCUMB,
  '01' ,
  CASE
        --PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN '01' --JAN PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN '02' --FEB
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN '03' --MAR
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN '04'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN '05'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN '06'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN '07'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN '08' --AUG
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN '09'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN '10' --OCT
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'NOV'
      THEN '11'
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'DEC'
      THEN '12'
      ELSE '00'
    END ,

  (CASE
        --PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'NOV'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'DEC'
      THEN TO_NUMBER(YEAR)
      ELSE TO_NUMBER(YEAR)
    END) 


UNION ALL

SELECT 
  FUND,
  ORG,
  ACCT,
  PROG,
  YEAR,
  SUM(S02_BUDGET + S02_BUDGET_ADJ) BUDG,
   S02_YTD_ACTV YEAR_TO_DATE,
   S02_ENCUMB ENCUMBRANCE,
  '01' AS SPERIOD,
  CASE
        --PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN '02' --JAN PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN '03' --FEB
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN '04' --MAR
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN '05'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN '06'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN '07'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN '08'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN '09' --AUG
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN '10'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN '11' --OCT
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'NOV'
      THEN '12'
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'DEC'
      THEN '01'
      ELSE '00'
    END AS SMONTH,

  (CASE
        --PERIOD 02
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'NOV'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'DEC'
      THEN TO_NUMBER(YEAR)+1
      ELSE TO_NUMBER(YEAR)
    END) AS S_YEAR
FROM SUMLEDGER , 
     FUNDING
WHERE FUNDING_NUMBER =  FUND
group by 
FUND,
  ORG,
  ACCT,
  PROG,
  YEAR,
   S02_YTD_ACTV ,
   S02_ENCUMB ,
  '01' ,
  CASE
        --PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN '02' --JAN PERIOD 01
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN '03' --FEB
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN '04' --MAR
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN '05'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN '06'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN '07'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN '08'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN '09' --AUG
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN '10'
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN '11' --OCT
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'NOV'
      THEN '12'
      WHEN SUBSTR(TO_CHAR(FUNDING_NUMBER,'MON-YYYY'),1,3) = 'DEC'
      THEN '01'
      ELSE '00'
    END ,

  (CASE
        --PERIOD 02
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JAN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'FEB'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'APR'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'MAY'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUN'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'JUL'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'AUG'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'SEP'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'OCT'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'NOV'
      THEN TO_NUMBER(YEAR)
      WHEN SUBSTR(TO_CHAR(FUNDING_START_DATE,'MON-YYYY'),1,3) = 'DEC'
      THEN TO_NUMBER(YEAR)+1
      ELSE TO_NUMBER(YEAR)
    END) 

有人可以帮我用 unpivot 函数重写这个吗?使用上述方法将需要我至少合并 14 次,因为有 14 个可能的句点/列快速抬头此表包含大约 98 列我已将此处的示例减少为少数列以便更好地解释而不是压倒。

这是我要复制的输出

"FUND"  "ORG"   "ACCT"  "PROG"  "YEAR"  "BUDG"  "YEAR_TO_DATE"  "ENCUMBRANCE"   "SPERIOD"   "SMONTH"    "S_YEAR"
"100001"    "3999"  "3220"  "06"    6   50  15  15  "01"    "01"    6
"100001"    "3999"  "3220"  "06"    7   50  15  15  "01"    "01"    7
"100001"    "3999"  "3220"  "06"    8   55  25  30  "01"    "01"    8
"100001"    "3999"  "3460"  "06"    6   55  20  20  "01"    "01"    6
"100001"    "3999"  "3220"  "06"    6   30  10  40  "01"    "02"    6
"100001"    "3999"  "3220"  "06"    8   52  15  30  "01"    "02"    8
"100001"    "3999"  "3460"  "06"    6   40  30  40  "01"    "02"    6
"100001"    "3999"  "3220"  "06"    7   30  30  40  "01"    "02"    7

【问题讨论】:

仍然试图了解这里发生了什么(如果我能理解这个问题并且我可以回答它,我会添加一个答案)。不过,快速观察一下,substr(to_char(some_date, 'MON-YYYY'), 1, 3) 可以写成to_char(some_date, 'MON') 更简洁有效; CASE 语句可以写得更紧凑,如下所示:CASE TO_CHAR(some_date, 'MON') WHEN 'JAN' THEN ... WHEN 'FEB' THEN ... - 这样你就不需要重复表达式 12 次。 【参考方案1】:

您在预期结果中的speriod 不正确。最后四行应该有 02。

试试这个:

select
  s.fund,
  s.org,
  s.acct,
  s.prog,
  s.year,
  s.budget + s.budget_adj budg,
  s.year_to_date,
  s.encumbrance,
  s.s_period,
  to_number(to_char(add_months(f.funding_start_date, s_period - 1), 'MM')) s_month,
  decode(to_char(f.funding_start_date,'MM'),'12',year + s_period - 1, year) s_year
from (
  select *
  from sumledger
  unpivot ( 
    (budget, budget_adj, year_to_date, encumbrance) 
    for s_period in (
      (s01_budget,s01_budget_adj,s01_ytd_actv,s01_encumb) as 1,
      (s02_budget,s02_budget_adj,s02_ytd_actv,s02_encumb) as 2)
  )
) s inner join funding f on s.fund = f.funding_number;

生产:

【讨论】:

你是很棒的古夫。谢谢!

以上是关于多列,多表列到行 unpivot的主要内容,如果未能解决你的问题,请参考以下文章

没有 UNPIVOT 的 Oracle SQL 列到行

具有不同日期的列到行

SQL 表列到数组

python pandas,某些列到行[重复]

python pandas,某些列到行[重复]

iOS 布局列到行