覆盖日期/句点的SQL查询覆盖默认日期

时间:2009-10-28 10:14:13

标签: sql sql-server override

有关构建Sql Server(2008)查询的任何想法,该查询将根据默认值或覆盖存在的情况向我说出项目的“日期特定价格”

因此,默认表可能如下所示 - 列Price,StartDate,EndDate(yyyy-M-d):

Default:  $10, 2010-1-1, 2010-2-1

Override表如下:

Override: $12, 2010-1-5, 2010-1-8

查询将返回:

Result:   $10, 2010-1-1, 2010-1-4
          $12, 2010-1-5, 2010-1-8
          $10, 2010-1-9, 2010-2-1

可能我会将它包装在存储过程或函数中,并在特定日期范围内调用它。

4 个答案:

答案 0 :(得分:0)

类似的东西:

SELECT
   D.Price, ISNULL(O.StartDate, D.StartDate), ISNULL(O.EndDate, D.EndDate)
FROM
   Default D
   LEFT JOIN
   Override O ON D.Price= O.Price

答案 1 :(得分:0)

正确的设计是只有一张桌子。您根本不需要覆盖表。只需在单个表中保持每一个 - 受日期范围的限制。查询也变得更加简单。

您的表格结构变为

CREATE TABLE Rates
(ID INT NOT NULL,
 Rate Decimal NOT NULL,
 FromDate NOT NULL,
 ToDate   NOT NULL,
 CONSTRAINT PK_RATES (ID,FromDate,ToDate))

然后查询变为

SELECT Rate FROM Rates WHERE ID = @ID AND FromDate = (SELECT MAX(FromDate) FROM Rates WHERE ID = @ID AND FromDate <= @Date) AND ToDate = (SELECT MIN(ToDate) FROM Rates WHERE ID = @ID AND ToDate >=@Date) 

答案 2 :(得分:0)

我认为你将不得不做这样的事情(假设你想要将覆盖日期分开,并且你想避免任何程序性的事情):

  1. 定义并填充实用程序表,列出可能与您相关的每个日期
  2. 构造一个SELECT,将来自此实用程序表的每个日期“标记”为i)属于覆盖日期或ii)属于默认日期
  3. 按日期和“标记”
  4. 对此SELECT的结果进行分组
  5. 将这些结果加回相应的价格信息

答案 3 :(得分:0)

有点晚了,但是正在寻找类似问题的解决方案而没有找到答案,所以试着煮一个。

一种解决方案可以是尝试调整第一组数据以适应第二组,在最后一步中,我们将两组,调整后的数据与叠加数据结合起来。

因此我们需要调整默认设置,这需要几个步骤。

假设: -

默认期间不会重叠。 重叠期间不会重叠。

重叠数据必须有超过一天的间隙,以确保任何调整都不会影响另一个重叠期;我们不会丢失相关的叠加值,因为我们会在最后一步将它们取回。

对于部分重叠的默认期间(重叠大于或等于默认期间)

如果期间开始日期与任何重叠期间重叠,我们会将开始日期更改为重叠期间的结尾加一天

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

我确定可能有另一种方法来实现一些递归方法所需的结果,但是现在这对我有效。

对于最后一步,如果值相同,我们可以尝试合并结果,但我不认为这是请求的。