2016-08-11 3 views
0

Источник Таблица DDL: -Как назначить счетчик на основе условия

CREATE TABLE temp (
    REG_ID  NUMBER(5) , 
    Pkg_DES  VARCHAR2(15), 
    PRD_DESC  VARCHAR2(15) 
    EVENT_DATE DATE, 
    event_type_cd VARCHAR2(15) 
) 

У меня есть вставки заявления тоже ниже -

insert into temp (REG_ID, Pkg_DES, PRD_DESC, EVENT_DATE, event_type_cd) 
select 1 , 'CC' , 'trail' , to_date('12/12/2016', 'mm/dd/yyyy') , 'new sub' from dual union all 
select 1 , 'CC' , 'trail' ,to_date('12/13/2016', 'mm/dd/yyyy') , 'exp' from dual union all  
select 1 , 'CC' , 'PAID' , to_date('12/14/2016', 'mm/dd/yyyy') , 'upsell' from dual union all 
select 1 , 'CC' , 'PAID' , to_date('12/15/2016', 'mm/dd/yyyy'), 'exp' from dual union all 
select 1 , 'CC' , 'PAID' , to_date('12/16/2016', 'mm/dd/yyyy') , 'renewal' from dual union all 
select 1 , 'CC' , 'PAID' , to_date('12/17/2016', 'mm/dd/yyyy') , 'renewal' from dual union all 
select 1 , 'aa' , 'trail' , to_date('12/12/2016', 'mm/dd/yyyy') , 'new sub' from dual union all 
select 1 , 'aa' , 'trail' , to_date('12/13/2016', 'mm/dd/yyyy') , 'exp' from dual union all  
select 1 , 'aa' , 'PAID' , to_date('12/14/2016', 'mm/dd/yyyy') , 'renewal' from dual union all 
select 1 , 'aa' , 'PAID' , to_date('12/15/2016', 'mm/dd/yyyy') , 'renewal' from dual union all 
select 1 , 'aa' , 'PAID' , to_date('12/16/2016', 'mm/dd/yyyy') , 'upsell' from dual union all 
select 1 , 'aa' , 'PAID' , to_date('12/17/2016', 'mm/dd/yyyy') , 'renewal' from dual; 

У меня есть требование, как это ниже

REG_ID | Pkg_DES | PRD_DESC | EVENT_DATE | event_type_cd 
-------+---------+----------+------------+-------------- 
    1 | CC  | trail | 12-12-2012 | new sub 
    1 | CC  | trail | 12-13-2012 | exp 
    1 | CC  | PAID | 12-14-2012 | upsell 
    1 | CC  | PAID | 12-15-2012 | exp 
    1 | CC  | PAID | 12-16-2012 | renewal 
    1 | CC  | PAID | 12-17-2012 | renewal 
    1 | aa  | trail | 12-12-2012 | new sub 
    1 | aa  | trail | 12-13-2012 | exp 
    1 | aa  | PAID | 12-14-2012 | renewal 
    1 | aa  | PAID | 12-15-2012 | renewal 
    1 | aa  | PAID | 12-16-2012 | upsell 
    1 | aa  | PAID | 12-17-2012 | renewal 

Выход, который мне нужен, как показано ниже:

REG_ID | Pkg_DES | PRD_DESC | EVENT_DATE | event_type_cd | renewal_cnt | is_ren | is_conv 
-------+---------+----------+------------+---------------+-------------+--------+-------- 
    1 | CC  | trail | 12-12-2012 | new sub  |  0  |  0 | 0 
    1 | CC  | trail | 12-13-2012 | exp   |  0  |  0 | 0 
    1 | CC  | PAID | 12-14-2012 | upsell  |  0  |  0 | 1 
    1 | CC  | PAID | 12-15-2012 | exp   |  0  |  0 | 1 
    1 | CC  | PAID | 12-16-2012 | renewal  |  1  |  1 | 0 
    1 | CC  | PAID | 12-17-2012 | renewal  |  2  |  1 | 0 
    1 | aa  | trail | 12-12-2012 | new sub  |  0  |  0 | 0 
    1 | aa  | trail | 12-13-2012 | exp   |  0  |  0 | 0 
    1 | aa  | PAID | 12-14-2012 | renewal  |  0  |  0 | 1 
    1 | aa  | PAID | 12-15-2012 | renewal  |  1  |  1 | 0 
    1 | aa  | PAID | 12-16-2012 | upsell  |  2  |  1 | 0 
    1 | aa  | PAID | 12-17-2012 | renewal  |  3  |  1 | 0 
  • Конверсия Logic: - Если PRD_DESC изменяется от Трейл оплачено 1-й раз, то она называется ПРЕОБРАЗОВАНИЯ продукт
  • Обновление Logic: - Если Paid Продукт обновляется с Выплачивается Пайде, то он называется RENEWAL product

  • renewal_cnt должен начинаться только с PAID на PAID. Если PAID для PAID имеет значение event_type_cd как exp, то счетчик не должен увеличиваться. Если тропа для оплаты имеет событие event_type_cd в качестве продления, то оно должно быть только нолем. события заказываются event_date

  • is_conv должно быть установлено в 1 для 1-го трейла к платной продукции.

  • is ren должно быть установлено равным 1 для оплаченного продукта.

У кого-то есть идея, как этого достичь?

+2

Вы еще что-нибудь пробовали? –

+0

@Tim Biegeleisen - Я попытался использовать функцию Rank и получить счетчик обновления, но это не сработало. :( – beckham

+0

Попробуйте функцию 'LAG' – cha

ответ

2

Решение @PonderStibbons в порядке, но, поскольку я сделал сам, не основанный на рекурсии, я отправляю его также. Обратите внимание, что будут различия для других наборов данных. Примечательно, что в этом запросе предполагается, что в пределах заданного диапазона одинаковых записей pkg_des группа записей с prd_descPAID не прерывается не PAID.Это не предположение, сделанное в рекурсивном решении, что может быть важный фактор, чтобы отменить мое решение:

select reg_id, pkg_des, prd_desc, event_date, event_type_cd, 
     case when prd_desc = 'PAID' 
       then greatest(0, -1+count(case when event_type_cd <> 'exp' then 1 end) 
         over (partition by reg_id, pkg_des, prd_desc 
          order by  event_date asc 
          rows between unbounded preceding and 0 preceding) 
        ) 
       else 0 
     end as renewal_cnt, 
     case when lag(prd_desc) over (partition by reg_id, pkg_des 
             order by  event_date asc) = 'PAID' 
       and prd_desc = 'PAID' 
       and event_type_cd = 'renewal' 
       then 1 
       else 0 
     end is_ren, 
     case when lag(prd_desc) over (partition by reg_id, pkg_des 
             order by  event_date asc) = 'trail' 
       and prd_desc = 'PAID' 
       then 1 
       else 0 
     end is_conv 
from  temp 
order by reg_id asc, 
     pkg_des desc, 
     event_date asc; 

Выхода одинаков для приведенных данных выборки:

REG_ID | Pkg_DES | PRD_DESC | EVENT_DATE | event_type_cd | renewal_cnt | is_ren | is_conv 
-------+---------+----------+------------+---------------+-------------+--------+-------- 
    1 | CC  | trail | 12-12-2012 | new sub  |  0  |  0 | 0 
    1 | CC  | trail | 12-13-2012 | exp   |  0  |  0 | 0 
    1 | CC  | PAID | 12-14-2012 | upsell  |  0  |  0 | 1 
    1 | CC  | PAID | 12-15-2012 | exp   |  0  |  0 | 0* 
    1 | CC  | PAID | 12-16-2012 | renewal  |  1  |  1 | 0 
    1 | CC  | PAID | 12-17-2012 | renewal  |  2  |  1 | 0 
    1 | aa  | trail | 12-12-2012 | new sub  |  0  |  0 | 0 
    1 | aa  | trail | 12-13-2012 | exp   |  0  |  0 | 0 
    1 | aa  | PAID | 12-14-2012 | renewal  |  0  |  0 | 1 
    1 | aa  | PAID | 12-15-2012 | renewal  |  1  |  1 | 0 
    1 | aa  | PAID | 12-16-2012 | upsell  |  2  |  0* | 0 
    1 | aa  | PAID | 12-17-2012 | renewal  |  3  |  1 | 0 

Я добавил звездочку где результат отличается от того, что вы указали в своем вопросе, но выше приведен результат, когда правила соблюдаются в письме.

+0

Привет Тринкот, ты гений. Запрос работает очень хорошо. Фактически вывод, который вы указали, является правильным. Запросы, предоставленные Пондером, тоже хорошо работали, но медленные, как я делаю это, на 20 млн. Записей. – beckham

+1

Добро пожаловать. Да, рекурсия часто имеет штраф за производительность, но в пользу рекурсивных запросов, я должен сказать, что считаю их более читабельными с точки зрения * правил *, и, следовательно, их легче поддерживать (в случае, если вам нужно что-то изменить позже). Просто говорю ... ;-) – trincot

+0

Я вижу -1 для некоторого обновления_cnt. Когда мы можем это ожидать? – beckham

2

В Oracle 11g можно использовать рекурсивный запрос, как показано ниже:

with 
    t as (
     select row_number() over (partition by pkg_des order by event_date) rn, 
      reg_id, pkg_des, prd_desc, event_date, event_type_cd 
     from temp), 
    th (rn, reg_id, pkg_des, prd_desc, event_date, event_type_cd, ren_cnt, is_ren, is_conv) 
    as (
     select rn, reg_id, pkg_des, prd_desc, event_date, event_type_cd, 0, 0, 0 
     from t where rn = 1 
     union all 
     select t.rn, t.reg_id, t.pkg_des, t.prd_desc, t.event_date, t.event_type_cd, 
      case when t.prd_desc = 'PAID' and th.prd_desc = 'PAID' 
        and t.event_type_cd <> 'exp' 
        then th.ren_cnt + 1 else th.ren_cnt end, 
      case when t.prd_desc = 'PAID' and th.prd_desc = 'PAID' 
        and t.event_type_cd <> 'exp' 
        then 1 else 0 end, 
      case when t.prd_desc = 'PAID' and th.prd_desc = 'trail' then 1 else 0 end 
     from t join th on t.pkg_des = th.pkg_des and t.rn = th.rn + 1) 
select pkg_des, prd_desc, event_date, event_type_cd, ren_cnt, is_ren, is_conv 
    from th order by pkg_des desc, rn; 

Выход:

PKG_DES   PRD_DESC  EVENT_DATE EVENT_TYPE_CD REN_CNT  IS_REN IS_CONV 
--------------- --------------- ----------- ------------- ---------- ---------- ---------- 
CC    trail   2016-12-12 new sub    0   0   0 
CC    trail   2016-12-13 exp     0   0   0 
CC    PAID   2016-12-14 upsell     0   0   1 
CC    PAID   2016-12-15 exp     0   0   0 
CC    PAID   2016-12-16 renewal    1   1   0 
CC    PAID   2016-12-17 renewal    2   1   0 
aa    trail   2016-12-12 new sub    0   0   0 
aa    trail   2016-12-13 exp     0   0   0 
aa    PAID   2016-12-14 renewal    0   0   1 
aa    PAID   2016-12-15 renewal    1   1   0 
aa    PAID   2016-12-16 upsell     2   1   0 
aa    PAID   2016-12-17 renewal    3   1   0 

подзапросов T только номера строк в правильном порядке. Основной подзапрос TH является рекурсивным. В строке 4 есть разница в столбце is_conv, но я следовал вашим правилам, поэтому условия в case when могут потребоваться небольшими корректировками.

Пояснения и примеры рекурсивных КТЭ: 1, 2.

+1

Хорошее решение! – trincot