如何将日期列表“合并”到日期范围

时间:2019-11-25 01:56:07

标签: sql sql-server gaps-and-islands

如何将日期列表合并到日期范围中,我需要将不同行中的一系列天合并到开始日期和结束日期的日期范围中。

Create Table #temp_dates
 (Str_Date DateTime,
 End_Date DateTime,
 Rate decimal(10,4))
 ;

 Insert Into #temp_dates
 Values ('2012-01-05 07:55:24.000','2012-03-03 12:25:02.000',0.001),
('2012-03-03 12:25:02.000','2012-03-04 15:28:16.000',0.001),
('2012-03-04 15:28:16.000','2012-08-23 05:14:07.000',0.001),
('2012-08-23 05:14:07.000','2013-04-24 15:04:25.000',0.001),
('2013-04-24 15:04:25.000','2015-04-13 05:37:59.000',0.0015),
('2015-04-13 05:37:59.000','2015-10-11 08:50:24.000',0.0015),
('2015-10-11 08:50:24.000','2016-03-19 23:58:35.000',0.0015),
('2016-03-19 23:58:35.000','2016-03-20 11:07:56.000',0.001),
('2016-03-20 11:07:56.000','2016-04-12 21:05:06.000',0.0015),
('2016-04-12 21:05:06.000','2016-04-12 22:31:41.000',0.001),
('2016-04-12 22:31:41.000','2016-04-20 00:45:32.000',0.0015),
('2016-04-20 00:45:32.000','2016-09-10 19:17:31.000',0.0015)

打开

StartDateTime   EndDateTime Rate
2012-01-05 07:55:24.000 2012-03-03 12:25:02.000 0.001
2012-03-03 12:25:02.000 2012-03-04 15:28:16.000 0.001
2012-03-04 15:28:16.000 2012-08-23 05:14:07.000 0.001
2012-08-23 05:14:07.000 2013-04-24 15:04:25.000 0.001
2013-04-24 15:04:25.000 2015-04-13 05:37:59.000 0.0015
2015-04-13 05:37:59.000 2015-10-11 08:50:24.000 0.0015
2015-10-11 08:50:24.000 2016-03-19 23:58:35.000 0.0015
2016-03-19 23:58:35.000 2016-03-20 11:07:56.000 0.001
2016-03-20 11:07:56.000 2016-04-12 21:05:06.000 0.0015
2016-04-12 21:05:06.000 2016-04-12 22:31:41.000 0.001
2016-04-12 22:31:41.000 2016-04-20 00:45:32.000 0.0015
2016-04-20 00:45:32.000 2016-09-10 19:17:31.000 0.0015

进入

StartDateTime   EndDateTime Rate
2012-01-05 07:55:24.000 2013-04-24 15:04:25.000 0.001
2013-04-24 15:04:25.000 2016-03-19 23:58:35.000 0.0015
2016-03-19 23:58:35.000 2016-03-20 11:07:56.000 0.001
2016-03-20 11:07:56.000 2016-04-12 21:05:06.000 0.0015
2016-04-12 21:05:06.000 2016-04-12 22:31:41.000 0.001
2016-04-12 22:31:41.000 2016-09-10 19:17:31.000 0.0015

2 个答案:

答案 0 :(得分:0)

这是一种空白和岛屿问题。在这种情况下,请使用lag()确定组从何处开始。然后对这些“开始”使用累积总和来定义要分组在一起的行。

最后一步是实际的汇总:

select rate, min(str_date), max(end_date)
from (select td.*,
             sum(case when prev_end_date = str_date then 0 else 1 end) over (partition by rate order by str_date) as grp
      from (select td.*,
                   lag(end_date) over (partition by rate order by str_date) as prev_end_date
            from temp_dates td
           ) td
     ) td
group by rate, grp
order by min(str_date);

Here是db <>小提琴。

答案 1 :(得分:0)

这是一个孤岛问题。您可以使用lag()和一个窗口总和来解决它。

select 
    min(StartDateTime) StartDateTime, 
    max(EndDateTime) EndDateTime,
    Rate
from (
    select
        t.*,
        sum(case when LagRate = Rate then 0 else 1 end) over(order by StartDateTime) grp
    from (
        select 
            t.*,
            lag(Rate) over(order by StartDateTime) LagRate
        from #temp_dates t
    ) t
) t
group by grp, Rate
order by min(StartDateTime)

第一个子查询将前一个Rate与每个记录相关联。然后,下一个子查询计算组:每次Rate更改时,都会启动一个新组。最后,外部查询汇总每个组中的记录,并提取每个组的最小StartDateTime和最大EndDateTime以及关联的Rate

Demo on DB Fiddle

StartDateTime       | EndDateTime         | Rate  
:------------------ | :------------------ | :-----
05/01/2012 07:55:24 | 24/04/2013 15:04:25 | 0.0010
24/04/2013 15:04:25 | 19/03/2016 23:58:35 | 0.0015
19/03/2016 23:58:35 | 20/03/2016 11:07:56 | 0.0010
20/03/2016 11:07:56 | 12/04/2016 21:05:06 | 0.0015
12/04/2016 21:05:06 | 12/04/2016 22:31:41 | 0.0010
12/04/2016 22:31:41 | 10/09/2016 19:17:31 | 0.0015