有点晚了,但正在寻找类似问题的解决方案,但没有找到答案,所以试图做一个。
一种解决方案是尝试调整第一组数据以适应第二组数据,在最后一步中,我们将合并这两组数据,调整后的数据与叠加数据。
所以我们需要调整默认设置,这需要几个步骤。
假设:-
默认期间不重叠。
重叠时期不会与自身重叠。
重叠数据必须有超过一天的差距,以确保任何调整都不会影响另一个重叠期;我们不会丢失相关的覆盖值,因为我们会在最后一步中取回它们。
对于部分重叠的默认周期(重叠大于或等于默认周期)
如果一个期间的开始日期与任何重叠期间重叠,我们会将开始日期更改为重叠期间的结束加上一天
Default: |<-------- P1 ------>|
Overlap: |<-----------O1------>|
=================================================================
Output: |<-----P1 ---->|
如果期间结束日期与任何重叠期间重叠,我们会将结束日期更改为重叠期间的开始减去一天
Default: |<-------- P1 ------>|
Overlap: |<-----------O1------>|
===================================================================
Output: |<--- P1 ---->|
如果默认时间段完全被重叠期覆盖,则删除它
Default: |<--- P1 --->|
Overlap: |<--------O1------>|
===================================================================
Output: nothing
对于被重叠周期打破的默认周期(重叠小于周期)
获取第一部分(从期初到第一个重叠期)
获取中间部分,即从任何重叠期结束到下一个重叠期开始。
获取最后一部分(从最后重叠到期末)
Default: |<---------------------------- P1 ------------------------------>|
Overlap: |<---O1--->| |<---O2-->| |<--O3->|
===================================================================
Output: |<-P1->| |<-P1->| |<-P1->| |<-P1->|
最后合并数据,得到结果
我们正在考虑的重叠类型
Default: |<---- P1 --->|
Overlap: |<-----------O1------>|
===================================================================
Output: |<---- P1 --->||<-----------O1------>|
让我们构建 T-SQL
With [System] as (
Select 1 [RowNum],cast('Jan 01,2017' as date) [StartDate],dateadd(day,-1,cast('Feb 01,2017' as date)) [EndDate],0500 [Value] union all
Select 2 [RowNum],cast('Feb 01,2017' as date) [StartDate],dateadd(day,-1,cast('Mar 01,2017' as date)) [EndDate],0700 [Value] union all
Select 3 [RowNum],cast('Mar 01,2017' as date) [StartDate],dateadd(day,-1,cast('Apr 01,2017' as date)) [EndDate],0900 [Value] union all
Select 4 [RowNum],cast('Apr 01,2017' as date) [StartDate],dateadd(day,-1,cast('May 01,2017' as date)) [EndDate],0700 [Value] union all
Select 5 [RowNum],cast('May 01,2017' as date) [StartDate],dateadd(day,-1,cast('Jun 01,2017' as date)) [EndDate],0900 [Value] union all
Select 6 [RowNum],cast('Jun 01,2017' as date) [StartDate],dateadd(day,-1,cast('Jul 01,9999' as date)) [EndDate],1500 [Value]
),Overrides as (
Select 1 [RowNum],cast('Feb 12,2017' as date) [StartDate],cast('Mar 25,2017' as date) [EndDate],1 [Value] union all
Select 2 [RowNum],cast('Mar 28,2017' as date) [StartDate],cast('May 15,2017' as date) [EndDate],2 [Value] union all
Select 3 [RowNum],cast('May 18,2017' as date) [StartDate],cast('May 20,2017' as date) [EndDate],3 [Value] union all
Select 4 [RowNum],cast('Jun 05,2017' as date) [StartDate],cast('Jun 08,2017' as date) [EndDate],4 [Value] union all
Select 5 [RowNum],cast('Jun 09,2017' as date) [StartDate],cast('Jun 16,2017' as date) [EndDate],5 [Value] union all
Select 6 [RowNum],cast('Jun 17,2017' as date) [StartDate],cast('Jun 22,2017' as date) [EndDate],6 [Value] union all
Select 7 [RowNum],cast('Jun 23,2017' as date) [StartDate],cast('Jun 27,2017' as date) [EndDate],7 [Value]
),PrepareOverridePeriods as (--if override periods have no gabs betwwen we need to merge them
Select p1.StartDate, p1.EndDate
from Overrides p1
left join Overrides p2 on p1.StartDate = DATEADD(day,1,p2.EndDate)
where p2.StartDate is null
union all
select p1.StartDate,p2.EndDate
from PrepareOverridePeriods p1
inner join Overrides p2 on p1.EndDate = DATEADD(day,-1,p2.StartDate)
),OverridePeriods as (
select ROW_NUMBER() over (order by StartDate) [RowNum],StartDate,MAX(EndDate) as EndDate
from PrepareOverridePeriods group by StartDate
),AdjustedPeriods as (
select s.RowNum,'Adj.' [type]
,isnull(dateadd(day,1,ShiftRight.EndDate),s.StartDate) [StartDate]
,isnull(dateadd(day,-1,ShiftLeft.StartDate),s.EndDate) [EndDate]
,s.Value
from System s
left outer join OverridePeriods ShiftRight on s.StartDate between ShiftRight.StartDate and ShiftRight.EndDate
left outer join OverridePeriods ShiftLeft on s.EndDate between ShiftLeft.StartDate and ShiftLeft.EndDate
left outer join OverridePeriods RemovePeriod on s.StartDate between RemovePeriod.StartDate and RemovePeriod.EndDate and s.EndDate between RemovePeriod.StartDate and RemovePeriod.EndDate
where RemovePeriod.StartDate is null
),SmallOverrides as ( --TODO: change SystemCalculated to AdjustSystemCalculatedPeriods
select ROW_NUMBER() over (partition by s.RowNum order by o.StartDate ) [RowNum],
o.RowNum [OverrideRowNum],o.StartDate [OverrideStartDate],o.EndDate [OverrideEndDate],s.Value [Value]
,s.RowNum [SystemRowNum],s.StartDate [SystemStartDate],s.EndDate [SystemEndDate]
from OverridePeriods o
inner join AdjustedPeriods s on o.StartDate between s.StartDate and s.EndDate and o.EndDate between s.StartDate and s.EndDate
)
--,FirstAndLastParts as (
--select [SystemRowNum],[type]
-- ,case when [type]='First' then min([SystemStartDate]) else dateadd(day,1,max(OverrideEndDate)) end [StartDate]
-- ,case when [type]='First' then dateadd(day,-1,min(OverrideStartDate)) else max([SystemEndDate]) end [EndDate]
-- ,min(Value) [Value]
-- from (select *,'First' [type] from SmallOverrides o union all
-- select *,'Last' [type] from SmallOverrides o) data
-- group by [SystemRowNum],[type]
--)
,FirstParts as (
select [SystemRowNum],'First' [type]
,min([SystemStartDate]) [StartDate]
,dateadd(day,-1,min(OverrideStartDate)) [EndDate]
,min(Value) [Value]
from SmallOverrides
group by [SystemRowNum]
),LastParts as (
select [SystemRowNum],'Last' [type]
,dateadd(day,1,max(OverrideEndDate)) [StartDate]
,max([SystemEndDate]) [EndDate]
,min(Value) [Value]
from SmallOverrides
group by [SystemRowNum]
),IntermediatParts as (
select s.SystemRowNum [RowNum],'Inter.' [type]
,dateadd(day,1,s.OverrideEndDate) [StartDate]
,dateadd(day,-1,e.OverrideStartDate) [EndDate]
,s.Value
from SmallOverrides s
left outer join SmallOverrides e on e.SystemRowNum=s.SystemRowNum and s.RowNum+1=e.RowNum
where e.RowNum is not null --remove the first and lasts
),AdjustedPeriodsFiltered as (--remove blocks that are broken to smaller pieces
select s.*
from AdjustedPeriods s
left outer join OverridePeriods o on o.StartDate between s.StartDate and s.EndDate and o.EndDate between s.StartDate and s.EndDate
where o.StartDate is null
),AllParts as (
select * from IntermediatParts union all --order by SystemRowNum,OverrideStartDate
select * from FirstParts union all
select * from LastParts union all
select * from AdjustedPeriodsFiltered
),Merged as (
select [RowNum],[type] [Source],StartDate,EndDate,Value,'System' [RecordType] from AllParts
union all
select [RowNum],'override' [Source],StartDate,EndDate,Value,'Override' [RecordType] from Overrides
)
select * from Merged order by StartDate
我们能否以不同的方式调整数据集,嗯,是的,另一种方法是从默认时段和覆盖时段的开始日期和结束日期获取所有预期值,然后重建一组新的时段,链接将其设置为默认值,将其与叠加层合并,我们得到了它。
相同的假设和步骤如下:-
With [System] as (
Select 1 [RowNum],cast('Jan 01,2017' as date) [StartDate],dateadd(day,-1,cast('Feb 01,2017' as date)) [EndDate],0500 [Value] union all
Select 2 [RowNum],cast('Feb 01,2017' as date) [StartDate],dateadd(day,-1,cast('Mar 01,2017' as date)) [EndDate],0700 [Value] union all
Select 3 [RowNum],cast('Mar 01,2017' as date) [StartDate],dateadd(day,-1,cast('Apr 01,2017' as date)) [EndDate],0900 [Value] union all
Select 4 [RowNum],cast('Apr 01,2017' as date) [StartDate],dateadd(day,-1,cast('May 01,2017' as date)) [EndDate],0700 [Value] union all
Select 5 [RowNum],cast('May 01,2017' as date) [StartDate],dateadd(day,-1,cast('Jun 01,2017' as date)) [EndDate],0900 [Value] union all
Select 6 [RowNum],cast('Jun 01,2017' as date) [StartDate],dateadd(day,-1,cast('Jul 01,9999' as date)) [EndDate],1500 [Value]
),Overrides as (
Select 1 [RowNum],cast('Feb 12,2017' as date) [StartDate],cast('Mar 25,2017' as date) [EndDate],1 [Value] union all
Select 2 [RowNum],cast('Mar 28,2017' as date) [StartDate],cast('May 15,2017' as date) [EndDate],2 [Value] union all
Select 3 [RowNum],cast('May 18,2017' as date) [StartDate],cast('May 20,2017' as date) [EndDate],3 [Value] union all
Select 4 [RowNum],cast('Jun 05,2017' as date) [StartDate],cast('Jun 08,2017' as date) [EndDate],4 [Value] union all
Select 5 [RowNum],cast('Jun 09,2017' as date) [StartDate],cast('Jun 16,2017' as date) [EndDate],5 [Value] union all
Select 6 [RowNum],cast('Jun 17,2017' as date) [StartDate],cast('Jun 22,2017' as date) [EndDate],6 [Value] union all
Select 7 [RowNum],cast('Jun 23,2017' as date) [StartDate],cast('Jun 27,2017' as date) [EndDate],7 [Value]
),PrepareOverridePeriods as (--if override periods have no gabs between we need to merge them
Select p1.StartDate, p1.EndDate
from Overrides p1
left join Overrides p2 on p1.StartDate = DATEADD(day,1,p2.EndDate)
where p2.StartDate is null
union all
select p1.StartDate,p2.EndDate
from PrepareOverridePeriods p1
inner join Overrides p2 on p1.EndDate = DATEADD(day,-1,p2.StartDate)
),OverridePeriods as (
select ROW_NUMBER() over (order by StartDate) [RowNum],StartDate,MAX(EndDate) as EndDate
from PrepareOverridePeriods group by StartDate
)
,AllDates as (
select ROW_NUMBER() over (order by [Date]) [RowNum],data.Date from (
select dateadd(day,-1,OverridePeriods.StartDate) [Date] from OverridePeriods union all
select dateadd(day,+1,OverridePeriods.EndDate) [Date] from OverridePeriods union all
select StartDate [Date] from [System] union all
select EndDate [Date] from [System] ) as data
)
,NewPeriods as (
select sy.RowNum, s.[Date] [StartDate],n.[Date] [EndDate] ,sy.Value
from AllDates s
left outer join AllDates n on n.RowNum=s.RowNum+1
left outer join OverridePeriods o on s.[Date] between o.StartDate and o.EndDate and n.[Date] between o.StartDate and o.EndDate
left outer join [System] sy on s.[Date] between sy.StartDate and sy.EndDate
where
s.RowNum % 2 =1 and o.StartDate is null--group it by 2 and remove overriden areas
)
,Merged2 as (
select [RowNum], StartDate,EndDate,Value,'System' [RecordType] from NewPeriods
union all
select [RowNum], StartDate,EndDate,Value,'Override' [RecordType] from Overrides
)
select * from Merged2 order by StartDate
我确信可能有另一种方法可以通过某种递归方法实现所需的结果,但现在这对我有用。
对于最后一步,如果值相同,我们可以尝试合并结果,但我认为没有要求。