如何UNPIVOT到多个列?

时间:2016-02-03 10:53:29

标签: oracle oracle11g oracle10g

我有一张如下图所示的图片enter image description here

我需要输出如下图像

enter image description here

我有一个使用union查询所需输出的查询

    select distinct cd_5 as ORG_UNIT_CD, upper('"'||nm_5||'"') as ORG_UNIT_NM, cd4 as PARENT_ORG_UNIT_CD, 5 as ORG_UNIT_LEVEL 
from TBL
where cd_5 <> 0
union
select distinct cd_4 as ORG_UNIT_CD, upper('"'||nm_4||'"') as ORG_UNIT_NM, cd_3 as PARENT_ORG_UNIT_CD, 4 as ORG_UNIT_LEVEL 
from TBL 
where cd_4 <> 0
union
select distinct cd_3 as ORG_UNIT_CD, upper('"'||nm_3||'"') as ORG_UNIT_NM, cd_2 as PARENT_ORG_UNIT_CD, 3 as ORG_UNIT_LEVEL 
from TBL 
where cd_3 <> 0
union
select distinct cd_2 as ORG_UNIT_CD, upper('"'||nm_2||'"') as ORG_UNIT_NM, cd_1 as PARENT_ORG_UNIT_CD, 2 as ORG_UNIT_LEVEL 
from TBL
where cd_2 <> 0
union
select distinct cd_1 as ORG_UNIT_CD, upper('"'||nm_1||'"') as ORG_UNIT_NM, 0 as PARENT_ORG_UNIT_CD, 1 as ORG_UNIT_LEVEL 
from TBL 
where cd_1 <> 0
order by ORG_UNIT_LEVEL

我需要一个简化的查询而不是这个。 Becoz我只给了五级heirachy,实际上我有20级。

4 个答案:

答案 0 :(得分:4)

以下是适用于您的数据的UNPIVOT(适用于Oracle 11+版本)示例:

DROP TABLE mytable;
CREATE TABLE mytable(
   OBJECT_ID INTEGER  NOT NULL PRIMARY KEY 
  ,CD_1      INTEGER  NOT NULL
  ,NM_1      VARCHAR(15) NOT NULL
  ,CD_2      INTEGER  NOT NULL
  ,NM_2      VARCHAR(28) NOT NULL
  ,CD_3      INTEGER  NOT NULL
  ,NM_3      VARCHAR(20) NOT NULL
  ,CD_4      INTEGER  NOT NULL
  ,NM_4      VARCHAR(28) NOT NULL
  ,CD_5      INTEGER  NOT NULL
  ,NM_5      VARCHAR(16) NOT NULL
  ,DT        VARCHAR(14) NOT NULL
);


insert into mytable
SELECT 53027429 AS OBJECT_ID,53001326 AS CD_1,'CEO & President' AS NM_1,53000330 AS CD_2,'Merck Manufacturing Division' AS NM_2,53011048 AS CD_3,'EMEA Operations' AS NM_3,54001626 AS CD_4,'HSC PLANT DIRECTION' AS NM_4,53027385 AS CD_5,'HSC NOT STERILE' AS NM_5,'4/24/2013 8:22' AS DT from dual
UNION ALL
SELECT 54010819,53001326,'CEO & President',54002711,'Merck Consumer Care',54007326,'MCC Emerging Markets',54010308,'Consumer Care - Asia Pacific',54010819,'MCC Singapore','8/23/201211:26' from dual
UNION ALL
SELECT 53025491,53001326,'CEO & President',53000330,'Merck Manufacturing Division',53011048,'EMEA Operations',54003518,'Rathdrum - Plant Manager',53020040,'Engineering & FM','5/22/2012 6:24' from dual
UNION ALL
SELECT 53023206,53001326,'CEO & President',53000321,'Corporate Finance',53000333,'MMD Finance',54001411,'Operations',54004358,'MMD Finance EMEA','5/31/2012 6:51' from dual
UNION ALL
SELECT 53021255,53001326,'CEO & President',53008586,'Global Human Health',54001286,'EUCan1',53013126,'Mid-Europe 1',53019000,'MER-1 Balkans','3/14/2013 7:06' from dual;

commit;


select distinct cd, nm, 
  case when parent=cd then 0 else parent end as parent, lvl 
from (
  select * from mytable
  unpivot (
      (cd, nm, parent) for lvl in ((CD_1, NM_1, CD_1) as 1,(CD_2, NM_2, CD_1) as 2,(CD_3, NM_3, CD_2) as 3,(CD_4, NM_4, CD_3) as 4, (CD_5, NM_5, CD_4) as 5)
  )
)
order by lvl;

输出:

        CD NM                               PARENT        LVL
---------- ---------------------------- ---------- ----------
  53001326 CEO & President                       0          1
  53000321 Corporate Finance              53001326          2
  53008586 Global Human Health            53001326          2
  54002711 Merck Consumer Care            53001326          2
  53000330 Merck Manufacturing Division   53001326          2
  53011048 EMEA Operations                53000330          3
  54001286 EUCan1                         53008586          3
  54007326 MCC Emerging Markets           54002711          3
  53000333 MMD Finance                    53000321          3
  54010308 Consumer Care - Asia Pacific   54007326          4
  54001626 HSC PLANT DIRECTION            53011048          4
  53013126 Mid-Europe 1                   54001286          4
  54001411 Operations                     53000333          4
  54003518 Rathdrum - Plant Manager       53011048          4
  53020040 Engineering & FM               54003518          5
  53027385 HSC NOT STERILE                54001626          5
  54010819 MCC Singapore                  54010308          5
  53019000 MER-1 Balkans                  53013126          5
  54004358 MMD Finance EMEA               54001411          5

19 rows selected.

答案 1 :(得分:1)

在Oracle-11g中使用 Unpivot

执行列到行操作,并使用decode来派生其他列值。

试试这个:

select distinct /*product_code,*/quantity as ORG_UNIT_CD,
decode(product_code,'cd1','"'||nm1||'"','cd2','"'||nm2||'"','cd3','"'||nm3||'"','cd4','"'||nm4||'"','cd5','"'||nm5||'"') as ORG_UNIT_NM,
decode(product_code,'cd1','0','cd2','cd1','cd3','cd2','cd4','cd3','cd5','cd4') as PARENT_ORG_UNIT_CD
from unpivot_test2
UNPIVOT(quantity FOR product_code in (cd1 as 'cd1',cd2 as 'cd2',cd3 as 'cd3', cd4 as 'cd4', cd5 as 'cd5'))
where quantity <> 0;;

答案 2 :(得分:0)

我怀疑你是在追求以下内容:

with dummy as (select 1 id
               from   dual
               connect by level <= 5)
select case when d.id = 1 then t.cd_1
            when d.id = 2 then t.cd_2
            when d.id = 3 then t.cd_3
            when d.id = 4 then t.cd_4
            when d.id = 5 then t.cd_5
       end org_unit_cd,
       case when d.id = 1 then t.nm_1
            when d.id = 2 then t.nm_2
            when d.id = 3 then t.nm_3
            when d.id = 4 then t.nm_4
            when d.id = 5 then t.nm_5
       end org_unit_nm,
       case when d.id = 1 then 0
            when d.id = 2 then t.cd_1
            when d.id = 3 then t.cd_2
            when d.id = 4 then t.cd_3
            when d.id = 5 then t.cd_4
       end parent_org_unit_cd,
       d.id org_unit_level
from   (select distinct cd_1,
                        cd_2,
                        cd_3,
                        cd_4,
                        cd_5,
                        '"'||upper(nm_1)||'"' nm_1,
                        '"'||upper(nm_2)||'"' nm_2,
                        '"'||upper(nm_3)||'"' nm_3,
                        '"'||upper(nm_4)||'"' nm_4,
                        '"'||upper(nm_5)||'"' nm_5
        from   tbl) t
       cross join dummy d
where  case when d.id = 1 then t.cd_1
            when d.id = 2 then t.cd_2
            when d.id = 3 then t.cd_3
            when d.id = 4 then t.cd_4
            when d.id = 5 then t.cd_5
       end != 0;

这简单地将每个不同的行从TBL复制5次,并在相关行上输出每个cd_N,nm_N和cd_n-1。以上将适用于10g和11g。

以下答案适用于11g:

select org_unit_cd,
       org_unit_nm,
       parent_org_unit_cd,
       org_unit_level
from   (select distinct cd_1,
                        cd_2,
                        cd_3,
                        cd_4,
                        cd_5,
                        '"'||upper(nm_1)||'"' nm_1,
                        '"'||upper(nm_2)||'"' nm_2,
                        '"'||upper(nm_3)||'"' nm_3,
                        '"'||upper(nm_4)||'"' nm_4,
                        '"'||upper(nm_5)||'"' nm_5,
                        0 cd_0
        from   tbl)
unpivot ((org_unit_cd, org_unit_nm, parent_org_unit_cd) for org_unit_level in ((cd_1, nm_1, cd_0) as 1,
                                                                               (cd_2, nm_2, cd_1) as 2,
                                                                               (cd_3, nm_3, cd_2) as 3,
                                                                               (cd_4, nm_4, cd_3) as 4,
                                                                               (cd_5, nm_5, cd_4) as 5))

答案 3 :(得分:0)

阿曼打败了我的白痴,所以我赞成他,但这里有一个例子,你可以跑去查看结果

WITH sample_data
     AS (SELECT 'Smith' family_name,
                'Pappy Smith' Great_Grandparent,
                'Fred Smith' GrandParent,
                'Joey Smith' Parent,
                'Joey Jr' Child
           FROM DUAL
         UNION ALL
         SELECT 'Jones',
                'Great Grammy Jones',
                'Grammy Jones',
                'Bob',
                'Bobby'
           FROM DUAL)
  SELECT family_name, source, val
    FROM sample_data UNPIVOT INCLUDE NULLS (val
           FOR (source)
           IN  (Great_Grandparent AS 'Great_Grandparent',
               Grandparent AS 'Granparent',
               Parent AS 'Parent',
               Child AS 'Child') )
ORDER BY family_name,
         DECODE (source,
                 'Great_Grandparent', 1,
                 'Granparent', 2,
                 'Parent', 3,
                 4)