Эффективно группировать строки в эпизоды без PL / SQL - PullRequest
0 голосов
/ 24 мая 2019

У меня есть набор данных с одной записью в день на одну сущность.Каждый день будет иметь только один статус, но статус может появляться в течение нескольких дней или только в один день.

Я хочу сгруппировать их в эпизоды.Поэтому, когда идентификатор изменяется, СОСТОЯНИЕ изменяется ИЛИ следующая запись находится на расстоянии более суток, и я хочу считать это новым эпизодом.

Я поиграл с аналитическими функциями, но, хотя я могу группировать по статусу, я затемне отслеживать каждый набор дней (хотя потенциально я мог бы сделать это за один проход на статус)

Я также мог бы сделать это в PL / SQL, но это невероятно медленно в моем тестировании.Я надеюсь, что есть способ выполнить это как запрос или, по крайней мере, частично предварительно обработать как запрос, чтобы цикл pl / sql был быстрее.

ID                      DAY         STATUS  Comment
E0000000000054245349    27-Feb-16   24      Start
E0000000000054245349    28-Feb-16   24  
E0000000000054245349    29-Feb-16   24  
E0000000000054245349    1-Mar-16    24  
E0000000000054245349    3-Mar-16    21      Gap & new status
E0000000000054245349    4-Mar-16    21  
            continuing daily
E0000000000054245349    12-Mar-16   21  
E0000000000054245349    13-Mar-16   21  
E0000000000054245349    14-Mar-16   21  
E0000000000054245349    15-Mar-16   40      No gap, but new status
E0000000000054245349    16-Mar-16   40  
E0000000000054245349    18-Mar-16   40      Gap, no new status
E0000000000054245349    19-Mar-16   40      
E0000000000054245349    1-Jan-17    21      Gap & new status
E0000000000054245349    2-Jan-17    21
E0000000000054245349    3-Jan-17    21      
E0000000000054245349    5-Jan-17    25      Gap, status and single day      

Мой идеальный набор данных хотел бы что-то вроде этого,Бонусные баллы, если он содержит предыдущий / следующий статус для записей, которые находятся за 1 день до / после, но я всегда могу получить их с последующим запросом, если это будет необходимо

ID                      START       END         STATUS
E0000000000054245349    27-Feb-16   1-Mar-16    24
E0000000000054245349    3-Mar-16    14-Mar-16   21
E0000000000054245349    15-Mar-16   16-Mar-16   40
E0000000000054245349    18-Mar-16   19-Mar-16   40
E0000000000054245349    1-Jan-17    3-Jan-17    21
E0000000000054245349    5-Jan-17    5-Jan-17    25      

Ответы [ 2 ]

5 голосов
/ 24 мая 2019

Вы можете сделать это легко, используя Метод Табибитозана :

select id, min(day) mnd, max(day) mxd, status
  from (
    select day - row_number() over (partition by id order by day) grp, id, day, status
      from t)
  group by id, grp, status
  order by id, grp;

dbfiddle demo

Это дает желаемый результат.Я не уловил эту фразу Бонусные баллы, если она содержит предыдущий / следующий статус для записей, которые находятся за 1 день до / после .В ваших выходных эпизодах может не быть строк за один день до / после.Если вы хотите статус из предыдущей / следующей строки, просто используйте lag() и lead ().Но если вы хотите, это будет только , если новый эпизод из-за изменения статуса, используйте аналитические функции условно:

select id, mnd, mxd, status, 
       case mnd when lag(mxd) over (partition by id order by mxd) + 1
                then lag(status) over (partition by id order by mxd) 
       end prev_status
  from (select id, min(day) mnd, max(day) mxd, status
          from (select day - row_number() over (partition by id order by day) grp, 
                       id, day, status
                  from t)
          group by id, grp, status)
  order by id, mnd;

... и то же самое для lead().

1 голос
/ 24 мая 2019

Это проблема пробела и острова - вы можете попробовать ниже:

select id, status,min(DAY) start,max(DAY) end
from
(
select *,island=row_number() over(partition by id order by day) - 
row_number() over(partition by id, status order by day) 
from tablename
)A group by id, status,island
...