Строка комкования, даты цикла - PullRequest
2 голосов
/ 16 октября 2019

Я хочу посмотреть на тип lead, и если этот тип одинаков для этой строки, то объединить эти даты, чтобы уместить их в одной строке.

У меня есть таблица ниже:

id    start_dt     end_dt    type
 1     1/1/19      2/21/19   cross
 1     2/22/19     6/5/19    cross
 1     6/6/19      8/31/19   cross
 1     9/1/19      10/3/19   AAAA
 1     10/4/19     10/4/19   cross
 1     10/5/19     10/6/19   AAAA
 1     10/7/19     10/10/19  AAAA
 1     10/11/19    12/31/99  cross

Ожидаемые результаты:

 id    start_dt    end_dt    type
 1     1/1/19      8/31/19   cross
 1     9/1/19      10/3/19   AAAA
 1     10/4/19     10/4/19   cross
 1     10/5/19     10/10/19  AAAA
 1     10/11/19    12/31/99  cross

Как мне получить результаты, которые будут похожи на ожидаемые результаты?

Я тестировал с lead lag rank и case expression, но ничего достойного добавить сюда. Я на правильном пути?

Ответы [ 3 ]

3 голосов
/ 16 октября 2019

Это проблема gaps-and-islands. Один вариант решения этой проблемы с помощью аналитической функции row_number():

select min(start_dt) as startdate, max(end_dt) as enddate, type
  from
  (
   with t(id, start_dt, end_dt,type) as
   (
    select 1, date'2019-01-01', date'2019-02-21', 'cross' from dual union all
    select 1, date'2019-02-22', date'2019-06-05', 'cross'  from dual union all
    select 1, date'2019-06-06', date'2019-08-31', 'cross'  from dual union all  
    select 1, date'2019-09-01', date'2019-10-03', 'AAAA'  from dual union all
    select 1, date'2019-09-04', date'2019-10-04', 'cross'  from dual union all   
    select 1, date'2019-10-05', date'2019-10-06', 'AAAA'  from dual union all
    select 1, date'2019-10-07', date'2019-10-10', 'AAAA'  from dual union all  
    select 1, date'2019-10-11', date'2019-12-31', 'cross'  from dual 
   )
   select type, 
          row_number() over (partition by id, type order by end_dt) as rn1,
          row_number() over (partition by id order by end_dt) as rn2,
          start_dt, end_dt
     from t
   ) tt
 group by type, rn1 - rn2
 order by enddate;

STARTDATE   ENDDATE     TYPE
---------   ---------   -----
01-JAN-19   31-AUG-19   cross
01-SEP-19   03-OCT-19   AAAA
04-SEP-19   04-OCT-19   cross
05-OCT-19   10-OCT-19   AAAA
11-OCT-19   31-DEC-19   cross

Демо

1 голос
/ 16 октября 2019

Если вы хотите посмотреть на соседние строки, чтобы найти группы, которые можно объединить, то я рекомендую lag(), чтобы найти, где начинаются группы, и накапливать сумму:

select id, type, min(start_dt), max(end_dt)
from (select t.*,
             sum(case when prev_end_dt >= start_dt - 1 then 0 else 1 end) over (partition by id, type order by start_dt) as grp
      from (select t.*,
                   lag(end_dt) over (partition by id, type order by start_dt) as prev_end_dt
            from t
           ) t
     ) t
group by id, type, grp
order by id, min(start_dt);

В частности, здесь будут обнаружены случаи, когда type не меняется, но есть промежуток времени, как показано this db <> fiddle для id = 2.

1 голос
/ 16 октября 2019

Я на самом деле думаю, что это довольно хороший пример функциональности Oracle Matching Function.

with t(id, start_dt, end_dt,type) as
   (
    select 1, date'2019-01-01', date'2019-02-21', 'cross' from dual union all
    select 1, date'2019-02-22', date'2019-06-05', 'cross'  from dual union all
    select 1, date'2019-06-06', date'2019-08-31', 'cross'  from dual union all  
    select 1, date'2019-09-01', date'2019-10-03', 'AAAA'  from dual union all
    select 1, date'2019-09-04', date'2019-10-04', 'cross'  from dual union all   
    select 1, date'2019-10-05', date'2019-10-06', 'AAAA'  from dual union all
    select 1, date'2019-10-07', date'2019-10-10', 'AAAA'  from dual union all  
    select 1, date'2019-10-11', date'2019-12-31', 'cross'  from dual 
   )
SELECT *
FROM t
MATCH_RECOGNIZE(ORDER BY start_dt
                MEASURES a.id AS ID,
                         A.start_dt AS START_DT,
                         NVL(LAST(B.end_dt), A.end_dt) AS END_DT,
                         a.type AS TYPE
                PATTERN (A B*)
                DEFINE B AS start_dt > PREV(start_dt) AND type = PREV(type));

Подробный учебник по этой теме можно найти здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...