数据透视:创建列以捕获重复的周期日期

时间:2019-03-27 18:21:42

标签: sql oracle pivot

我有下表。从周期到程序的联接是基于日期的。 有数以百万计的PGMID条目,因此我一直在考虑枢轴功能,但是我无法对PGMID进行硬编码。任何想法/帮助将不胜感激。 我确实有能力编辑数据库中的表。

表:周期

 ID     START_CYCLE END_CYCLE
 4400   7/22/2018   8/3/2018
 4400   8/4/2018    8/5/2018
 4400   8/6/2018    8/6/2018
 4400   8/7/2018    8/9/2018
 4400   8/10/2018   9/6/2018
 4400   9/7/2018    9/7/2018
 4400   9/8/2018    9/9/2018
 4400   9/10/2018   12/31/9999     

表:程序

PGMID  START_DT    END_DT
 101    8/4/2018   9/10/2018
 102    9/8/2018   9/8/2018
 103    9/10/2018  NULL

输出:

 ID   START_CYCLE   END_CYCLE  PGMID       
 4400  7/22/2018    8/3/2018     
 4400   8/4/2018    8/5/2018    101
 4400   8/6/2018    8/6/2018    101
 4400   8/7/2018    8/9/2018    101
 4400   8/10/2018   9/6/2018    101
 4400   9/7/2018    9/7/2018    101
 4400   9/8/2018    9/9/2018    101
 4400   9/8/2018    9/9/2018    102
 4400   9/10/2018   12/31/9999  103

有重复的周期条目,我不想重复任何日期。

 4400   9/8/2018    9/9/2018    101
 4400   9/8/2018    9/9/2018    102

预期输出:

 ID   START_CYCLE   END_CYCLE  PROGRAM1  PROGRAM2       
 4400  7/22/2018    8/3/2018     
 4400   8/4/2018    8/5/2018    101
 4400   8/6/2018    8/6/2018    101
 4400   8/7/2018    8/9/2018    101
 4400   8/10/2018   9/6/2018    101
 4400   9/7/2018    9/7/2018    101
 4400   9/8/2018    9/9/2018    101      102
 4400   9/10/2018   12/31/9999  103

2 个答案:

答案 0 :(得分:3)

select * 
  from (
    select id, start_cycle, end_cycle, pgmid, case when rn > 5 then 0 else rn end rn
      from (
        select id, start_cycle, end_cycle, pgmid, 
               row_number() over (partition by id, start_cycle, end_cycle order by pgmid) rn
          from cycle c
          left join program p on p.start_dt <= c.end_cycle and c.start_cycle <= p.end_dt ))
  pivot (listagg(pgmid, ',') within group (order by pgmid) 
         for rn in (1 program1, 2 program2, 3 program3, 4 program4, 5 program5, 0 others))
  order by id, start_cycle
  • 像往常一样保留联接数据
  • 添加按每个周期划分并按pgmid排序的row_number(),
  • 如果该数字超过某个数字(在我的情况下为5),则分配0
  • 使用此列进行数据透视。前五列与往常一样建立,最后一列可能包含更多程序,称为others
  • 而不是通常在枢轴minmax中使用listagg

如果每个循环中有超过5个程序,则需要这些步骤来显示所有程序。其余的都在others中。如果您知道最多只能有3个程序,则可以简化此查询。

如果您希望每个程序在不同的列中并且最大列数未知,那么它就是动态枢轴问题。在堆栈溢出中已经描述了一些解决方案,但是这些大多数都是解决方法。

在此示例中,一个循环中最多有8个程序:

with 
  cycle(id, start_cycle, end_cycle) as (
    select 4400, date '2018-07-22', date '2018-08-03' from dual union all
    select 4400, date '2018-08-04', date '2018-08-05' from dual union all
    select 4400, date '2018-08-06', date '2018-08-06' from dual union all
    select 4400, date '2018-08-07', date '2018-08-09' from dual union all
    select 4400, date '2018-08-10', date '2018-09-06' from dual union all
    select 4400, date '2018-09-07', date '2018-09-07' from dual union all
    select 4400, date '2018-09-08', date '2018-09-09' from dual union all
    select 4400, date '2018-09-10', date '9999-12-31' from dual ), 
  program(pgmid, start_dt, end_dt) as (
    select 101, date '2018-08-04', date '2018-09-10' from dual union all
    select 104, date '2018-08-06', date '2018-08-07' from dual union all
    select 105, date '2018-08-06', date '2018-08-07' from dual union all
    select 106, date '2018-08-06', date '2018-08-07' from dual union all
    select 107, date '2018-08-06', date '2018-08-07' from dual union all
    select 108, date '2018-08-06', date '2018-08-07' from dual union all
    select 109, date '2018-08-06', date '2018-08-07' from dual union all
    select 110, date '2018-08-07', date '2018-08-07' from dual union all
    select 102, date '2018-09-08', date '2018-09-08' from dual union all
    select 103, date '2018-09-10', null  from dual )
select * 
  from (
    select id, start_cycle, end_cycle, pgmid, case when rn > 5 then 0 else rn end rn
      from (
        select id, start_cycle, end_cycle, pgmid, 
               row_number() over (partition by id, start_cycle, end_cycle order by pgmid) rn
          from cycle c
          left join program p on p.start_dt <= c.end_cycle and c.start_cycle <= p.end_dt ))
  pivot (listagg(pgmid, ',') within group (order by pgmid) 
         for rn in (1 program1, 2 program2, 3 program3, 4 program4, 5 program5, 0 others))
  order by id, start_cycle

结果:

    ID START_CYCLE END_CYCLE   PROGRAM1  PROGRAM2  PROGRAM3  PROGRAM4  PROGRAM5  OTHERS
 ----- ----------- ----------- --------- --------- --------- --------- --------- ------------
  4400 2018-07-22  2018-08-03                                                    
  4400 2018-08-04  2018-08-05  101                                               
  4400 2018-08-06  2018-08-06  101       104       105       106       107       108,109
  4400 2018-08-07  2018-08-09  101       104       105       106       107       108,109,110
  4400 2018-08-10  2018-09-06  101                                               
  4400 2018-09-07  2018-09-07  101                                               
  4400 2018-09-08  2018-09-09  101       102                                     
  4400 2018-09-10  9999-12-31  101                                               

dbfiddle demo

答案 1 :(得分:0)

1-您必须添加“按START_CYCLE,END_CYCLE分组” 2-在选择部分中必须添加group_concat(PGMID分隔符',')

我不了解oracle,但在mysql中是:

select ..., group_concat(PGMID separator ',') as PGMIDs, ... 
from ... 
join ... 
where ... 
group by START_CYCLE, END_CYCLE 

希望对您有所帮助。