SQL Server中的第一个记录结束日期和下一个记录开始日期之间重叠

问题描述

我有以下类型的数据,我需要以下类型的输出

输入:

id   startdate  enddate
1    21/01/2019 23/01/2019
1    23/01/2019 24/01/2019
1    24/01/2029 27/01/2019
1    29/01/2019 02/02/2019

输出

id  startdate   enddate
1   21/01/2019  27/01/2019
1   29/01/2019  02/02/2019

我们需要使用匹配第一条记录enddate和第n条记录startdate的逻辑。

解决方法

这是一个空白问题,您希望将“相邻”日期分组在一起。这是使用窗口函数的一种方法:想法是将当前开始日期与“上一个”行的结束日期进行比较,并使用窗口总和来定义组:

select id,min(startdate) startdate,max(enddate) enddate
from (
    select t.*,sum(case when startdate = lag_enddate then 0 else 1 end) over(partition by id order by startdate) grp
    from (
        select t.*,lag(enddate) over(partition by id order by startdate) lag_enddate
        from mytable t
    ) t
) t
group by id,grp

Demo on DB Fiddle -首先感谢Sander用于创建DDL语句:

id | startdate  | enddate   
-: | :--------- | :---------
 1 | 2019-01-21 | 2019-01-27
 1 | 2019-01-29 | 2019-02-02
,

看看

  1. NEXT VALUE FOR方法,在2016年及以后可用

  2. 使用CTE或子查询(在2008年可用),在其中使用前一个值作为联接在自己的表上联接。这是我用来显示备份增长的示例脚本

    declare @backupType char(1),@DatabaseName sysname
    
     set @DatabaseName   = db_name() --> Name of current database,null for all databaseson server
     set @backupType     ='D'        /* valid options are:
                                     D = Database 
                                     I = Database Differential 
                                     L = Log 
                                     F = File or Filegroup 
                                     G = File Differential 
                                     P = Partial 
                                     Q = Partial Differential
                                     */
    
    
    
     select  backup_start_date,backup_finish_date,DurationSec,database_name,backup_size,PreviouseBackupSize,backup_size-PreviouseBackupSize as growth,KbSec= format(KbSec,'N2')
     FROM (
     select backup_start_date,datediff(second,backup_start_date,b.backup_finish_date) as DurationSec,b.database_name,b.backup_size/1024./1024. as backup_size,case when datediff(second,b.backup_finish_date) >0 
             then ( b.backup_size/1024.)/datediff(second,b.backup_finish_date)
             else 0 end as KbSec
     --,b.compressed_backup_size,(      
             select top (1) p.backup_size/1024./1024. 
               from msdb.dbo.backupset p 
              where p.database_name = b.database_name
                and p.database_backup_lsn< b.database_backup_lsn
                 and type=@backupType
              order by p.database_backup_lsn desc
             ) as PreviouseBackupSize
     from msdb.dbo.backupset as b
     where @DatabaseName IS NULL OR database_name =@DatabaseName
     and type=@backupType
     )as A
     order by backup_start_date desc
    
  3. 使用“ cursor local fast_forward”游标逐行遍历数据,并使用临时表存储和保留先前的值

,

这是一个可行的通用表表达式解决方案。

样本数据

create table data
(
  id int,startdate date,enddate date
);

insert into data (id,startdate,enddate) values
(1,'2019-01-21','2019-01-23'),(1,'2019-01-23','2019-01-24'),'2019-01-24','2019-01-27'),'2019-01-29','2019-02-02');

解决方案

-- determine start dates
with cte_start as
(
  select s.id,s.startdate
  from data s
  where not exists ( select 'x'
                     from data e
                     where e.id = s.id
                       and e.enddate = s.startdate )
),-- determine date boundaries
cte_startnext as
(
  select s.id,s.startdate,lead(s.startdate) over (partition by s.id order by s.startdate) as startdate_next
  from cte_start s
)
-- determine periods
select sn.id,sn.startdate,e.enddate
from cte_startnext sn
cross apply ( select top 1 e.enddate
              from data e
              where e.id = sn.id
                and  e.startdate >= sn.startdate
                and (e.startdate <  sn.startdate_next or sn.startdate_next is null)
              order by e.enddate desc ) e
order by sn.id,sn.startdate;

结果

id startdate  enddate
-- ---------- ----------
1  2019-01-21 2019-01-27
1  2019-01-29 2019-02-02

Fiddle查看解决方案和中间CTE结果的建立。