SQL Server 中第一条记录结束日期和下一条记录开始日期之间的重叠
Posted
技术标签:
【中文标题】SQL Server 中第一条记录结束日期和下一条记录开始日期之间的重叠【英文标题】:Overlapping between first record enddate and next record start date in SQL Server 【发布时间】:2020-11-03 08:12:06 【问题描述】:我有以下类型的数据,我需要以下类型的输出。
输入:
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
的逻辑。
【问题讨论】:
几个问题:[1] 你真的在使用 SQL Server 2008 吗? Microsoft 不再支持此产品... [2] 您自己已经尝试过什么?向我们展示您的尝试,以便我们更好地指导您。 [3] 为什么要添加标签common-table-expression
?这是解决方案的要求吗?
从输入和输出数据样本中问题很清楚,但您没有回答我之前评论中的任何个问题...
我用的是SQL server 2016,没有条件只用CTE
【参考方案1】:
这是一个间隙和孤岛问题,您希望将“相邻”日期组合在一起。这是使用窗口函数的一种方法:想法是将当前开始日期与“上一个”行的结束日期进行比较,并使用窗口总和来定义组:
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 语句:
编号 |开始日期 |结束日期 -: | :--------- | :--------- 1 | 2019-01-21 | 2019-01-27 1 | 2019-01-29 | 2019-02-02【讨论】:
【参考方案2】:看看
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”逐行遍历数据,并使用临时表存储和比较上一个值
【讨论】:
【参考方案3】:这是一个可以使用公用表表达式的解决方案。
样本数据
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
Fiddle 查看解决方案和中间 CTE 结果的建立。
【讨论】:
以上是关于SQL Server 中第一条记录结束日期和下一条记录开始日期之间的重叠的主要内容,如果未能解决你的问题,请参考以下文章