Совокупные даты в пределах определенного дневного диапазона

У меня есть таблица с идентификаторами и датами, которые сгруппированы по близким датам

1       24/05/2010

10      18/06/2012
10      20/06/2012
10      21/06/2012

10      21/02/2014

10      04/07/2014

10      12/12/2016

1004    18/07/2016

1007    01/01/2017
1007    02/02/2017
1007    03/02/2017

1007    31/08/2017


create table tt ( id int, startdate date);  
Insert into TT values (1,'24/05/2010');
Insert into TT values (10,'18/06/2012');
Insert into TT values (10,'20/06/2012');
Insert into TT values (10,'21/06/2012');
Insert into TT values (10,'21/02/2014');
Insert into TT values (10,'04/07/2014');
Insert into TT values (10,'12/12/2016');
Insert into TT values (1004,'18/07/2016');
Insert into TT values (1007,'01/01/2017');
Insert into TT values (1007,'02/02/2017');
Insert into TT values (1007,'03/02/2017');
Insert into TT values (1007,'31/08/2017');

Я пытаюсь объединить перекрывающиеся даты и даты с промежутками максимум 90 дней и вывести их в одну строку, показывающую диапазон дат, сгруппированный по id, чтобы конечный результат был похож на:

1       24/05/2010  24/05/2010
10      18/06/2012  21/06/2012
10      21/02/2014  21/02/2014
10      04/07/2014  04/07/2014
10      12/12/2016  12/12/2016
1004    18/07/2016  18/07/2016
1007    01/01/2017  03/02/2017
1007    31/08/2017  31/08/2017

2 ответа

Хорошо, и вот еще одно решение с использованием только LAG а также LEAD вместо рекурсивного запроса:

WITH prv AS (SELECT id, startdate, lag(startdate) over (PARTITION BY id ORDER BY startdate) prev_date
             FROM tt)
   , NXT AS (SELECT id, startdate, lead(startdate) over (PARTITION BY id ORDER BY startdate) next_start
            FROM prv
           WHERE prev_date IS NULL OR prev_date < startdate - 90)
SELECT id,startdate
     , NVL((SELECT MAX(startdate) 
              FROM tt
             WHERE tt.id = nxt.id
               AND tt.startdate BETWEEN nxt.startdate AND nxt.next_start - 1)
          , startdate) enddate
  FROM nxt

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

WITH ord AS (SELECT id, startdate, ROW_NUMBER() over(PARTITION BY ID ORDER BY startdate) ord FROM tt) -- Connect every record with a number
   , rek(ord, id, startdate, enddate) AS 
         (SELECT ord, id, startdate, startdate FROM ord WHERE ord = 1 -- Take the first record of every group
          UNION ALL
          -- Then recursively take the next record
          SELECT rek.ord + 1
               , ord.id
               -- If the distance between old enddate and new startdate is <= 90 keep the startdate from the previous record otherwise take new one
               , CASE WHEN rek.enddate + 90 => ord.startdate
                      THEN rek.startdate
                      ELSE ord.startdate
                END
               , ord.startdate
            FROM rek
            JOIN ORD
              ON ord.ord = rek.ord+1
              AND ord.id = rek.id)
-- Cumulate data and keep only one record per id, startdate combination
SELECT id, startdate, MAX(enddate) enddate
  FROM rek
GROUP BY id, startdate
ORDER BY id, startdate
Другие вопросы по тегам