如何根据列调整日期和不同记录

时间:2016-07-27 06:22:34

标签: sql oracle

REG_ID| EVENT_TYPE_CD    | EVENT_DATE | PACKAGE_DESC    |PRODUCT_TYPE|TERM_START_DATE|TERM_END_DATE  
------|------------------|------------|-----------------|------------|---------------|----------  

11156 | NEW SUBSCRIPTION |  23-FEB-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 23-FEB-16  
11156 | CANCELLATION     |  23-FEB-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 23-FEB-16  
11156 | UPSELL           |  23-FEB-16 | CONNECTED CARE  |GOODWILL    | 23-FEB-16     | 22-MAR-16  
11156 | CANCELLATION     |  11-MAR-16 | CONNECTED CARE  |GOODWILL    | 23-FEB-16     | 11-MAR-16  
11156 | UPSELL           |  14-MAR-16 | CONNECTED CARE  |GOODWILL    | 14-APR-16     | 13-APR-17  
11156 | EXPIRATION       |  14-APR-16 | CONNECTED CARE  |GOODWILL    | 14-MAR-16     | 13-APR-17  
11163 | UPSELL           |  23-FEB-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 23-FEB-16  
11163 | CANCELLATION     |  23-FEB-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 22-MAR-16    
17215 | NEW SUBSCRIPTION |  18-JAN-16 | CONNECTED CARE  |TRIAL       | 18-JAN-16     | 17-JAN-17  
17215 | NEW SUBSCRIPTION |  18-JAN-16 | GUIDANCE        |TRIAL       | 18-JAN-16     | 17-APR-16  
17215 | CANCELLATION     |  22-FEB-16 | GUIDANCE        |TRIAL       | 18-JAN-16     | 22-FEB-16  
17215 | UPSELL           |  25-FEB-16 | GUIDANCE        |GOODWILL    | 25-FEB-16     | 24-APR-16  
17215 | EXPIRATION       |  25-APR-16 | GUIDANCE        |GOODWILL    | 25-FEB-16     | 24-APR-16  
17215 | NEW SUBSCRIPTION |  18-JAN-16 | REMOTE          |TRIAL       | 18-JAN-16     | 17-APR-16  
17215 | UPSELL           |  25-FEB-16 | REMOTE          |GOODWILL    | 25-FEB-16     | 24-APR-16  
17215 | NEW SUBSCRIPTION |  18-JUN-16 | REMOTE          |PAID        | 18-JUN-16     | 17-JUL-16  
17215 | UPSELL           |  25-JUL-16 | REMOTE          |GOODWILL    | 25-JUL-16     | 24-AUG-16 

我需要的输出是所有东西都需要按EVENT_DATE(事件系列)排序

  1. 如果'商誉'EVENT_DATE在'试用'产品EVENT_DATE之后 然后将其视为“试用”。如果'商誉'EVENT_DATE跟随a '付费'产品EVENT_DATE然后将其视为'付费'并调整 TERM_END_DATE(REMOTE示例没有时的理想情况 特定PACKAGE_DESC的取消或EXPIRATION event_type_cd 在REG_ID)

  2. 如果在取消后有事件,则忽略取消(11163显示:这是因为没有新的 取消后的活动)

  3. 如果有多个商誉 在跟踪之后,我们需要在最后的TERM_END_DATE中占用 周期需要指定为TERM_END_DATE(REG_ID 17215和GUIDANCE)。
  4. EXPIRATION RECORD应始终存在,其term_start_date 需要调整到Cycle的1st的Term_start_date 记录。
  5. REG_ID| EVENT_TYPE_CD    | EVENT_DATE | PACKAGE_DESC    |PRODUCT_TYPE|TERM_START_DATE| TERM_END_DATE  
    ------|------------------|------------|-----------------|------------|---------------|----------  
    
    11156 | NEW SUBSCRIPTION |  23-FEB-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 13-APR-17  
    11156 | EXPIRATION       |  14-APR-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 13-APR-17  
    11163 | UPSELL           |  23-FEB-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 23-FEB-16  
    11163 | CANCELLATION     |  23-FEB-16 | CONNECTED CARE  |PAID        | 23-FEB-16     | 22-MAR-16  
    17215 | NEW SUBSCRIPTION |  18-JAN-16 | CONNECTED CARE  |TRIAL       | 18-JAN-16     | 17-JAN-17  
    17215 | NEW SUBSCRIPTION |  18-JAN-16 | GUIDANCE        |TRIAL       | 18-JAN-16     | 24-APR-16  
    17215 | EXPIRATION       |  25-APR-16 | GUIDANCE        |TRAIL       | 18-JAN-16     | 24-APR-16  
    17215 | NEW SUBSCRIPTION |  18-JAN-16 | REMOTE          |TRIAL       | 18-JAN-16     | 24-APR-16  
    17215 | NEW SUBSCRIPTION |  18-JUN-16 | REMOTE          |PAID        | 18-JUN-16     | 24-AUG-16 
    

1 个答案:

答案 0 :(得分:2)

规则非常广泛,使用PL / SQL代码可能会获得更好的结果和性能,因为它可以在迭代游标时使用变量。

不过,我认为以下查询可能会满足您的需求:

select  reg_id, 
        event_type_cd,
        event_date,
        package_desc,
        case product_type when 'GOODWILL' then coalesce(prev_product_type, 'TRIAL')
            else product_type
        end as product_type,
        case event_type_cd when 'EXPIRATION' then first_term_start_date
            else term_start_date
        end as term_start_date,
        case next_product_type when 'GOODWILL' then next_term_end_date
            else term_end_date
        end as term_end_date
from    (select reg_id, 
                event_type_cd,
                event_date,
                package_desc,
                product_type,
                term_start_date,
                term_end_date,
                first_value(term_start_date) over (
                    partition by reg_id, package_desc 
                    order by event_date, term_end_date, event_type_cd desc) as first_term_start_date,
                lead(term_end_date, 1) over (
                    partition by reg_id, package_desc 
                    order by event_date, term_end_date, event_type_cd desc) as next_term_end_date,
                lag(product_type, 1) over (
                    partition by reg_id, package_desc 
                    order by event_date, term_end_date, event_type_cd desc) as prev_product_type,
                lead(product_type, 1) over (
                    partition by reg_id, package_desc 
                    order by event_date, term_end_date, event_type_cd desc) as next_product_type
        from    (select reg_id, 
                        event_type_cd,
                        event_date,
                        package_desc,
                        product_type,
                        term_start_date,
                        term_end_date,
                        lead(product_type, 1, '-') over (
                            partition by reg_id, package_desc 
                            order by event_date, term_end_date, event_type_cd desc) as next_product_type
                from    mytable)
                where   not (event_type_cd = 'CANCELLATION' and next_product_type <> '-')
                and     not (product_type = 'GOODWILL' and next_product_type = 'GOODWILL')
                )
where    not (    product_type = 'GOODWILL' 
              and event_type_cd not in ('EXPIRATION', 'CANCELLATION') 
              and prev_product_type is not null)
order by reg_id, package_desc, event_date, term_end_date, event_type_cd desc

查询具有两级嵌套子查询。

最内层查询仅用于获取周期内下一条记录的 product_type (即在 reg_id 的同一分区内和 package_desc )。

中间查询使用该信息消除:

  • '取消'记录,除非它们是他们周期的最后记录;
  • 连续'GOODWILL'记录,只留下最后一个序列 - 这是最后一个是暂时的,但现阶段仍然需要;

中间查询还会重新获取周期中下一条记录的 product_type ,因为它现在可能因已删除的记录而发生更改。此外,它确定:

  • 周期中第一条记录的 term_start_date ;
  • 周期中下一条记录的 term_end_date ;
  • 循环中上一条记录的 product_type ;

最后,外部查询使用此信息:

  • product_type 设置为上一条记录的(如果之前没有,则为“TRIAL”),如果它涉及“GOODWILL”记录;
  • term_start_date 设置为周期中第一条记录的,如果它涉及“EXPIRATION”记录;
  • 如果下一条记录涉及'GOODWILL'记录,
  • term_end_date 设置为周期中下一条记录的

“GOODWILL”记录(在上面第一个项目中的更改之前)被排除在结果之外,除非它们与周期中的第一条记录相关,或者对应于“EXPIRATION”或“CANCELLATION”记录。 / p>

order by子句使用您在评论中提到的顺序,并使用额外的event_type_cd desc来确保“取消或过期的EVENT_TYPE_CD将始终遵循新订阅或UPSELL特别是REG_ID,PACKAGE_DESC“。这是因为幸运的是,“NEW SUBSCRIPTION”和“UPSELL”都是按字母顺序出现,而不是“取消”和“EXPIRATION”,所以按降序排列,我们将它们排序正确。