Объединить записи для перекрывающихся дат - PullRequest
0 голосов
/ 09 июня 2018

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

Перед объединением:

Item Code               Start_date       End_date
==============          ===========      ===========
111                     15-May-2004      20-Jun-2004
111                     22-May-2004      07-Jun-2004
111                     20-Jun-2004      13-Aug-2004
111                     27-May-2004      30-Aug-2004
111                     02-Sep-2004      23-Dec-2004
222                     21-May-2004      19-Aug-2004 

Требуемый вывод:

Item Code               Start_date       End_date
==============          ===========      ===========
111                     15-May-2004      30-Aug-2004
111                     02-Sep-2004      23-Dec-2004
222                     21-May-2004      19-Aug-2004 

Вы можете создать пример данных, используя

create table item(item_code  number, start_date date, end_date date);

insert into item values (111,to_date('15-May-2004','DD-Mon-YYYY'),to_date('20-Jun-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('22-May-2004','DD-Mon-YYYY'),to_date('07-Jun-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('20-Jun-2004','DD-Mon-YYYY'),to_date('13-Aug-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('27-May-2004','DD-Mon-YYYY'),to_date('30-Aug-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('02-Sep-2004','DD-Mon-YYYY'),to_date('23-Dec-2004','DD-Mon-YYYY'));
insert into item values (222,to_date('21-May-2004','DD-Mon-YYYY'),to_date('19-Aug-2004','DD-Mon-YYYY'));

commit;

Ответы [ 4 ]

0 голосов
/ 09 июня 2018

с помощью приведенных выше ответов я могу упростить это, как показано ниже

WITH max_dates AS
 (
   SELECT
      item_code  
     ,start_date 
     ,end_date
     ,Max(end_date)  
      Over (PARTITION BY item_code  
            ORDER BY start_date 
            ) AS max_date 
   FROM   item
 )  ,
 max_dates1 as 
 (
 select max_dates.* , lag(max_date) over(partition by item_code order by 1) as MPD from max_dates
 )
 select ITEM_CODE,start_date,end_date from max_dates1  
 WHERE MPD  < start_date
   OR MPD  IS NULL 
0 голосов
/ 09 июня 2018

В SQL Server вы можете попробовать это.Это даст желаемый результат, но с точки зрения производительности запрос может замедлиться, когда требуется проверить большое количество данных.

DECLARE @item Table(item_code  int, start_date date, end_date date);

insert into @item values (111,'15-May-2004','20-Jun-2004');
insert into @item values (111,'22-May-2004','07-Jun-2004');
insert into @item values (111,'20-Jun-2004','13-Aug-2004');
insert into @item values (111,'27-May-2004','30-Aug-2004');
insert into @item values (111,'02-Sep-2004','23-Dec-2004');
insert into @item values (222,'21-May-2004','19-Aug-2004');


SELECT * FROM @item WHERE item_code IN (SELECT item_code FROM @item GROUP BY item_code) AND 
(start_date IN (SELECT max(start_date) FROM @item GROUP BY item_code) or start_date In (SELECT min(start_date) FROM @item GROUP BY item_code))
0 голосов
/ 09 июня 2018

Это разновидность проблемы разрывов и островков.Сначала вычислите максимальную предыдущую конечную дату для каждой строки.Затем отфильтруйте строки, у которых начальная дата текущей строки превышает максимальную дату, это начало новой группы, а конечная дата группы находится в следующей строке.

WITH max_dates AS
 (
   SELECT
      item_code  
     ,start_date 
     ,Max(end_date)  -- get the maximum prevous end_date
      Over (PARTITION BY item_code  
            ORDER BY start_date 
            ROWS BETWEEN Unbounded Preceding AND 1 Preceding) AS max_prev_date 
     ,Max(end_date)  -- get the maximum overall date (only needed for the last group)
      Over (PARTITION BY item_code) AS max_date 
   FROM   item
 )   
SELECT  
   item_code  
  ,start_date 
  ,Coalesce(Lead(max_prev_date)     -- next row got the end date for the current row
            Over (PARTITION BY item_code  
                  ORDER BY start_date) 
           ,max_date ) AS end_date  -- no next row for the last row --> overall maximum end_date

FROM max_dates
WHERE max_prev_date  < start_date -- maximum previous end date is less than current start date --> start of a new group
   OR max_prev_date  IS NULL      -- first row
0 голосов
/ 09 июня 2018

Код для этого типа проблемы довольно сложно.Вот один подход, который работает довольно хорошо:

with item (item_code, start_date, end_date) as (
      select 111,to_date('15-05-2004','DD-MM-YYYY'),to_date('20-06-2004','DD-MM-YYYY') from dual union all
      select 111,to_date('22-05-2004','DD-MM-YYYY'),to_date('07-06-2004','DD-MM-YYYY') from dual union all
      select 111,to_date('20-06-2004','DD-MM-YYYY'),to_date('13-08-2004','DD-MM-YYYY') from dual union all
      select 111,to_date('27-05-2004','DD-MM-YYYY'),to_date('30-08-2004','DD-MM-YYYY') from dual union all
      select 111,to_date('02-09-2004','DD-MM-YYYY'),to_date('23-12-2004','DD-MM-YYYY') from dual union all
      select 222,to_date('21-05-2004','DD-MM-YYYY'),to_date('19-08-2004','DD-MM-YYYY') from dual
     ),
     id as (
      select item_code, start_date as dte, count(*) as inc
      from item
      group by item_code, start_date
      union all
      select item_code, end_date, - count(*) as inc
      from item
      group by item_code, end_date
     ),
     id2 as (
      select id.*, sum(inc) over (partition by item_code order by dte) as running_inc
      from id
     ),
     id3 as (
      select id2.*, sum(case when running_inc = 0 then 1 else 0 end) over (partition by item_code order by dte desc) as grp
      from id2
     )
select item_code, min(dte) as start_date, max(dte) as end_date
from id3
group by item_code, grp;

и rextester для его проверки.

Что это делает?Хороший вопрос.Идея в этих проблемах состоит в том, чтобы определить смежные группы.Этот метод делает это путем подсчета количества «начинается» и «заканчивается» до определенной даты.Когда значение равно 0, группа заканчивается.

Конкретные шаги заключаются в следующем:

(1) Разбейте все даты на отдельные строки вместе с индикатором того, является ли датадата начала или окончания.Этот индикатор является ключевым для определения диапазонов - +1 для «входа» и «-1» для выхода.

(2) Рассчитать промежуточную сумму индикаторов.0 в этой сумме являются концами перекрывающихся диапазонов.

(3) Выполните обратную кумулятивную сумму нулей, чтобы идентифицировать группы.

(4) Объедините, чтобы получить окончательные результаты.

Вы можете посмотреть на каждый из CTE, чтобы увидеть, что происходит с данными.

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