我有以下类型的数据,我需要以下类型的输出。
输入:
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
DB Fiddle上的演示-Sander首先创建了DDL语句:
id|startdate|enddate-:|:--------|:---------2019-01-21|2019-01-271|2019-01-29|2019-02-02
查看
-
NEXT VALUE FOR方法,适用于2016年及以后的
-
使用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 , backup_finish_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,backup_start_date,b.backup_finish_date) >0 then ( b.backup_size/1024.)/datediff(second,backup_start_date,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
-
使用";游标本地fast_forward";逐行循环数据,并使用临时表存储&compare前值
这里有一个可以使用公共表表达式的解决方案。
样本数据
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'),
(1, '2019-01-24', '2019-01-27'),
(1, '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
查看解决方案的构建和中间CTE结果。