我在一个表中有一个日期范围列表,该范围可以是开放式的(enddate = null):
Index startdate enddate
1 2018-07-13 NULL
2 2018-11-14 2018-11-16
3 2018-11-15 2018-11-15
查询测试数据:
DECLARE @ScheduleTable Table([Index] int not null, StartDate DateTime not null, EndDate DateTime null)
insert into @ScheduleTable ([Index], StartDate, EndDate)
values
(1,'2018-07-13',null)
, (2,'2018-11-14','2018-11-16')
, (3,'2018-11-15','2018-11-15')
select*from @ScheduleTable
如何编写一个查询,以“填补空缺”并返回以下结果:
Index startdate enddate
1 2018-07-13 2018-11-13
2 2018-11-14 2018-11-14
3 2018-11-15 2018-11-15
2 2018-11-16 2018-11-16
1 2018-11-17 NULL
查询显示预期结果:
select
1 as [Index], '2018-07-13' as StartDate, '2018-11-13' as EndDate
UNION ALL
select
2 as [Index], '2018-11-14', '2018-11-14'
UNION ALL
select
3 as [Index], '2018-11-15', '2018-11-15'
UNION ALL
select
2 as [Index], '2018-11-16', '2018-11-16'
UNION ALL
select
1 as [Index], '2018-11-17', null
我希望答案不涉及参数/临时表等。如果有帮助,我可以使用日期维度表。
在上面的示例中,Index = 1的条目是开放式的,并从7.13开始。在11.14上被Index = 2中断。然后,Index = 2在11.15上被Index = 3打断。索引= 2然后从11.16重新开始。紧随其后的Index = 1是从11.17开始重新启动
索引决定了优先顺序,因此Index = 2将覆盖11.14-11.16上的Index = 1,Index = 3将覆盖11.15上的Index = 2 。
这是我当前使用lead()的查询:
DECLARE @MinDate DateTime = '2015-01-01'
DECLARE @MaxDate DateTime = '2020-01-01'
select
row_number() over(partition by dealid order by ss.StartDate, ss.id) as [Index]
, ss.startdate
, ss.enddate
, case when ss.enddate is null then
dateadd(d,-1,lead(ss.startdate,1,@MaxDate) over(partition by dealid order by ss.startdate, ss.id))
else ss.enddate end
as EndDate
from
[dbo].[Schedule]ss
where ss.enabled = 1
答案 0 :(得分:0)
我可以使用以下方法解决问题:
步骤:
查询以填充测试数据:
DECLARE @ScheduleTable Table([Index] int not null, StartDate DateTime not null, EndDate DateTime null)
insert into @ScheduleTable ([Index], StartDate, EndDate)
values
(1,'2018-07-13',null)
, (2,'2018-11-14','2018-11-16')
, (3,'2018-11-15','2018-11-15')
解决方案:
DECLARE @MinDate Date = dateadd(year,-2,getdate())
DECLARE @MaxDate DateTime = dateadd(year,2,getdate())
select
min(dt) as StartDate
, max(dt) as EndDate
, dense_rank() over(Order by [Index]) [Index]
from
(
select
--Create "groups" using a raw Rank minus dense_rank, partitioned by [Index]
rank() over(order by dt) - dense_rank() over(partition by [Index] order by dt) qlt,
[Index], dt
from
(
select
--Apply row_number to identify which schedule takes precedence on a given day
--Index=2 takes precedence over Index=1
row_number() over(partition by inr.[date] order by ss.[Index] desc) rm,
[date] dt
, ss.*
from
(
--Obtain Table of Dates from DateDimension table
select
[date]
from
[dbo].[DateDimension]dd
where dd.[date] >= @MinDate
and dd.[date] <= @MaxDate
)inr
--join schedules to DateDimension table
left join
(
select *
from
@ScheduleTable
)ss
on ss.StartDate <= inr.[date]
and (ss.enddate >= inr.[date]
or ss.enddate is null)
)inr2
--Exclude any Schedule that is not row_number=1
where inr2.rm = 1
and inr2.[Index] is not null
)inr3
--Group on Index first then Rank minus dense_rank, partitioned by [Index]
group by [Index], qlt
order by StartDate
, [Index]
结果:
StartDate EndDate Index
2018-07-13 2018-11-13 1
2018-11-14 2018-11-14 2
2018-11-15 2018-11-15 3
2018-11-16 2018-11-16 2
2018-11-17 2020-11-12 1