MSSQL:在月度休息的2个日期之间生成日期

时间:2017-04-20 15:12:30

标签: sql-server datetime intervals

苦苦挣扎......

我有一个包含以下列的表:

Type        varchar
StartDate   datetime
EndDate     datetime
Interval    int

我想要的是一个带有type列的结果表,以及开始日期和结束日期之间的所有日期,使用间隔作为它们之间的月份间隔。

例如,如果我表中唯一的行是:

'Test', '2017-01-01', '2019-01-01', 6

我想要一个包含5行的结果表,其中'Test'作为每行的Type,以及一个来自的日期列:

'2017-01-01', 
'2017-07-01', 
'2018-01-01', 
etc.

我已经创建了一个Calendar表甚至是DateRange函数,我在其中传递了开始日期,结束日期和月份间隔,它返回了我想要的所有日期,但由于它是一个表值函数我不喜欢似乎可以用另一个表中的数据来调用它。

我该怎么做?

感谢。

1 个答案:

答案 0 :(得分:1)

我经常使用TVF创建动态日期/时间范围。计数/日历表也可以解决问题,但UDF提供了一些额外的功能。例如,您提供Range,DatePart和Increment

Declare @YourTable table ([Type] varchar(25),StartDate date,EndDate date,Interval int)
Insert Into @YourTable values
('Test','2017-01-01','2019-01-01', 6)

Select A.[Type]
      ,B.*
 From  @YourTable A
 Cross Apply [dbo].[udf-Range-Date](A.StartDate,A.EndDate,'MM', A.Interval) B

<强>返回

Type    RetSeq  RetVal
Test    1       2017-01-01
Test    2       2017-07-01
Test    3       2018-01-01
Test    4       2018-07-01
Test    5       2019-01-01

感兴趣的UDF

CREATE FUNCTION [dbo].[udf-Range-Date] (@R1 datetime,@R2 datetime,@Part varchar(10),@Incr int)
Returns Table
Return (
    with cte0(M)   As (Select 1+Case @Part When 'YY' then DateDiff(YY,@R1,@R2)/@Incr When 'QQ' then DateDiff(QQ,@R1,@R2)/@Incr When 'MM' then DateDiff(MM,@R1,@R2)/@Incr When 'WK' then DateDiff(WK,@R1,@R2)/@Incr When 'DD' then DateDiff(DD,@R1,@R2)/@Incr When 'HH' then DateDiff(HH,@R1,@R2)/@Incr When 'MI' then DateDiff(MI,@R1,@R2)/@Incr When 'SS' then DateDiff(SS,@R1,@R2)/@Incr End),
         cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
         cte2(N)   As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
         cte3(N,D) As (Select 0,@R1 Union All Select N,Case @Part When 'YY' then DateAdd(YY, N*@Incr, @R1) When 'QQ' then DateAdd(QQ, N*@Incr, @R1) When 'MM' then DateAdd(MM, N*@Incr, @R1) When 'WK' then DateAdd(WK, N*@Incr, @R1) When 'DD' then DateAdd(DD, N*@Incr, @R1) When 'HH' then DateAdd(HH, N*@Incr, @R1) When 'MI' then DateAdd(MI, N*@Incr, @R1) When 'SS' then DateAdd(SS, N*@Incr, @R1) End From cte2 )

    Select RetSeq = N+1
          ,RetVal = D 
     From  cte3,cte0 
     Where D<=@R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1) 
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1) 
*/