我正在思考需要通过SQL解决的以下问题。设有自然数的区间[a,b]和[a,b]的所有子集的(有限的)区间A组。我们想确定补充auf A,即一组间隔B,使得A + B = [a,b],A和B成对不相交。
例如:给定[a,b] = 2017年的日期("所有日期"),以及3月 - 6月,4月,4月 - 7月和11月的间隔("可能的天数& #34)。现在产生间隔jan-feb,aug-oct和dec("不可能的日子")。所有间隔都是相应的。应该通过开始日期和结束日期来定义。
我尝试了以下内容。制作2017年的日历,并检查每天是否包含在两个间隔中。从这些日子开始,构建相应的间隔。到目前为止,它似乎很复杂,我开始认为这种解决方案在SQL方面有点不合时宜。但也许它只是我的实施。你怎么看?你想知道更好的方法吗?
来自法兰克福的问候,
约翰
答案 0 :(得分:0)
只要您使用已知的固定范围,您就可以轻松找到候选者作为任何当前间隔之外的开始或结束。然后根据日期顺序将它们配对:
declare @RangeStart date
declare @RangeEnd date
select @RangeStart = '20170101',@RangeEnd = '20171231'
declare @intervals table (
StartAt date not null,
EndAt date not null
)
insert into @intervals (StartAt,EndAt) values
('20170301','20170630'),
('20170401','20170430'),
('20170401','20170731'),
('20171101','20171130')
;With Starts as (
select
@RangeStart as StartDT
where
not exists (select * from @intervals i where @RangeStart between i.StartAt and i.EndAt) --Start outside an interval
union all
select
DATEADD(day,1,i1.EndAt)
from
@intervals i1
left join
@intervals i2
on
DATEADD(day,1,i1.EndAt) between i2.StartAt and i2.EndAt --No succeeding interval
where
i2.EndAt is null
), Ends as (
select
@RangeEnd as EndDT
where
not exists (select * from @intervals i where @RangeEnd between i.StartAt and i.EndAt) --End outside an interval
union all
select
DATEADD(day,-1,i1.StartAt)
from
@intervals i1
left join
@intervals i2
on
DATEADD(day,-1,i1.StartAt) between i2.StartAt and i2.EndAt --No preceding interval
where
i2.StartAt is null
), OrderedStarts as (
select StartDT,ROW_NUMBER() OVER (ORDER BY StartDT) as rn
from Starts where StartDT between @RangeStart and @RangeEnd
), OrderedEnds as (
select EndDT,ROW_NUMBER() OVER (ORDER BY EndDt) as rn
from Ends where EndDT between @RangeStart and @RangeEnd
)
select
os.StartDT,oe.EndDT
from
OrderedStarts os
inner join
OrderedEnds oe
on
os.rn = oe.rn
结果:
StartDT EndDT
---------- ----------
2017-01-01 2017-02-28
2017-08-01 2017-10-31
2017-12-01 2017-12-31
即 - 有效的开始日期是我们的范围的开始或任何其他间隔之后的第二天,前提是它不与另一个间隔重叠。同样为有效目的。