转动表重复值 - 是否可能?

时间:2016-03-09 06:47:08

标签: sql oracle excel-vba vba excel

我有一个表 - RATE如下:

LOCATION_ID RATE_TYPE_CODE     RATE_1 START_DATE END_DATE 
----------- -------------- ---------- ---------- ---------
          1 A                     .04            30-JUN-15
          1 A                     .02 01-JUL-15  30-JUN-16
          1 A                       0 01-JUL-16           
          2 A                     .05 01-JUL-04           
          3 A                     .09 01-JUL-04           
          2 B                     .28 01-JUL-04  30-APR-16
          2 B                     .34 01-MAY-16  30-APR-17
          2 B                      .3 01-MAY-17           

我必须从Excel工作簿宏查询此表,并以列式格式获取位置ID的费率,以日期范围分隔。因此,对于01-APR-2016生效日期,我必须在Excel中以柱状格式获取适用的01-APR-2017费率:

enter image description here

我尝试了什么:根据生效日期以及一年之后获取正确的费率。这是查询:

select *
  from rate r
 where     (   r.start_date is null
            or r.start_date <= to_date ('01-APR-2016')
            or     r.start_date >= to_date ('01-APR-2016')
               and r.start_date <= add_months (to_date ('01-APR-2016'), 12))
       and (   r.end_date is null
            or r.end_date >= add_months (to_date ('01-APR-2016'), 12)
            or r.end_date >= to_date ('01-APR-2016'));

输出:

LOCATION_ID RATE_TYPE_CODE     RATE_1 START_DATE END_DATE 
----------- -------------- ---------- ---------- ---------
          1 A                     .02 01-JUL-15  30-JUN-16
          1 A                       0 01-JUL-16           
          2 A                     .05 01-JUL-04           
          3 A                     .09 01-JUL-04           
          2 B                     .28 01-JUL-04  30-APR-16
          2 B                     .34 01-MAY-16  30-APR-17

我认为这样的支点是可能的,但我看不出办法。对此的任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

我找到了一个可以忍受的答案:

with rate as
         (select 1 location_id,
                 'A' rate_type_code,
                 0.04 rate_1,
                 null as start_date,
                 to_date ('30 JUN 2015') end_date
            from dual
          union all
          select 1 location_id,
                 'A' rate_type_code,
                 0.02 rate_1,
                 to_date ('01 JUL 2015') as start_date,
                 to_date ('30 JUN 2016') end_date
            from dual
          union all
          select 1,
                 'A',
                 0,
                 to_date ('01 JUL 2016'),
                 null
            from dual
          union all
          select 2,
                 'A',
                 0.05,
                 to_date ('01 JUL 2004'),
                 null
            from dual
          union all
          select 3,
                 'A',
                 0.09,
                 to_date ('01 JUL 2004'),
                 null
            from dual
          union all
          select 2,
                 'B',
                 0.28,
                 to_date ('01 JUL 2004'),
                 to_date ('30 APR 2016')
            from dual
          union all
          select 2,
                 'B',
                 0.34,
                 to_date ('01 MAY 2016'),
                 to_date ('30 APR 2017')
            from dual
          union all
          select 2,
                 'B',
                 0.30,
                 to_date ('01 MAY 2017'),
                 null
            from dual),
     mod_rate as
         (select r.location_id,
                 r.rate_type_code,
                 case
                     when nvl (r.start_date, to_date ('01-JAN-2000')) >
                              :my_start_date then
                         nvl (r.start_date, to_date ('01-JAN-2000'))
                     else
                         :my_start_date
                 end
                     as start_date,
                 case
                     when nvl (r.end_date, to_date ('31-DEC-2099')) <
                              nvl ( :my_end_date,
                                   add_months ( :my_start_date, 12)) then
                         nvl (r.end_date, to_date ('31-DEC-2099'))
                     else
                         nvl ( :my_end_date, add_months ( :my_start_date, 12))
                 end
                     as end_date,
                 r.rate_1
            from rate r
           where     (   r.start_date is null
                      or r.start_date <= :my_start_date
                      or     r.start_date >= :my_start_date
                         and r.start_date <=
                                 nvl ( :my_end_date,
                                      add_months ( :my_start_date, 12)))
                 and (   r.end_date is null
                      or r.end_date >=
                             nvl ( :my_end_date,
                                  add_months ( :my_start_date, 12))
                      or r.end_date >= :my_start_date)),
     date_range as
         (  select mr.rate_type_code,
                   mr.start_date,
                   mr.end_date,
                   lead (
                       mr.start_date,
                       1)
                   over (partition by mr.rate_type_code
                         order by mr.rate_type_code, mr.start_date)
                       next_start_date
              from mod_rate mr
          group by mr.rate_type_code, mr.start_date, mr.end_date
          order by mr.rate_type_code, mr.start_date, mr.end_date),
     final_date_range as
         (select dr.rate_type_code, dr.start_date, dr.end_date
            from date_range dr
           where not (    nvl (dr.next_start_date, dr.start_date) >
                              dr.start_date
                      and nvl (dr.next_start_date, dr.end_date) < dr.end_date))
select fdr.rate_type_code,
       fdr.start_date,
       fdr.end_date,
       (select mr.rate_1
          from mod_rate mr
         where     mr.rate_type_code = fdr.rate_type_code
               and mr.start_date <= fdr.start_date
               and mr.end_date >= fdr.end_date
               and mr.location_id = 1)
           as rates_for_location_1,
       (select mr.rate_1
          from mod_rate mr
         where     mr.rate_type_code = fdr.rate_type_code
               and mr.start_date <= fdr.start_date
               and mr.end_date >= fdr.end_date
               and mr.location_id = 2)
           as rates_for_location_2,
       (select mr.rate_1
          from mod_rate mr
         where     mr.rate_type_code = fdr.rate_type_code
               and mr.start_date <= fdr.start_date
               and mr.end_date >= fdr.end_date
               and mr.location_id = 3)
           as rates_for_location_3
  from final_date_range fdr;

<强>输出:

RATE_TYPE_CODE START_DATE END_DATE    RATES_FOR_LOCATION_1 RATES_FOR_LOCATION_2 RATES_FOR_LOCATION_3
-------------- ---------- ----------- -------------------- -------------------- --------------------
A              1/04/2016  30/06/2016  0.02                 0.05                 0.09
A              1/07/2016  1/04/2017   0                    0.05                 0.09
B              1/04/2016  30/04/2016                       0.28                   
B              1/05/2016  1/04/2017                        0.34                   

我可以在Excel中接收数据后简单地转置这些数据并以所需格式获取。