使用SQL Server每隔一周计算日期列表

时间:2019-04-12 15:05:02

标签: sql-server tsql

要根据给定数据填充表(SQL Server):

StartData-04/1/2019,EndData-04/30/2019,Interval = 2

根据间隔跳过一周。就像显示的预期结果一样。

输出:

04/01/2019
04/02/2019
04/03/2019
04/04/2019
04/05/2019
04/06/2019
04/07/2019
** Skip 7 days
04/15/2019
04/16/2019
04/17/2019
04/18/2019
04/19/2019
04/20/2019
04/21/2019
** Skip 7 days
04/29/2019
04/30/2019

4 个答案:

答案 0 :(得分:2)

使用从零开始的计数表,这非常简单。

DECLARE @StartDate date = '20190401',
        @EndDate date = '20190430',
        @interval int = 2;

WITH 
E(n) AS(
    SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0))E(n)
),
E2(n) AS(
    SELECT a.n FROM E a, E b
),
E4(n) AS(
    SELECT a.n FROM E2 a, E2 b
),
cteTally(n) AS(
    SELECT TOP(DATEDIFF( dd, @StartDate, @EndDate) + 1)
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) -1
    FROM E4
)
SELECT DATEADD( DD, n, @StartDate)
FROM cteTally
WHERE (n/7 + 1)% @interval = 1;

当然可以将其转换为内联表值函数,以结合性能和易用性。

CREATE FUNCTION getDateListWithIntervals(
    @StartDate date,
    @EndDate date,
    @interval int
)
RETURNS TABLE
AS RETURN
    WITH 
    E(n) AS(
        SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0))E(n)
    ),
    E2(n) AS(
        SELECT a.n FROM E a, E b
    ),
    E4(n) AS(
        SELECT a.n FROM E2 a, E2 b
    ),
    cteTally(n) AS(
        SELECT TOP(DATEDIFF( dd, @StartDate, @EndDate) + 1)
            ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) -1
        FROM E4
    )
    SELECT DATEADD( DD, n, @StartDate) calDate
    FROM cteTally
    WHERE (n/7 + 1)% @interval = 1;

答案 1 :(得分:1)

使用CTE实现了此目的

 with t0(i) as (select 0 union all select 0 union all select 0 union all select 0 union all select 0 union all select 0),
         t1(i) as (select 0 from t0 a, t0 b),
          n(i) as (select row_number()over(order by i) from t1),
          tbl1 as ( select 0 i, dateadd(month, datediff(month,0,getdate()),0) daysOfMonth
                    union all
                    select n.i , dateadd(day,n.i, dateadd(month, datediff(month,0,getdate()),0)) daysOfMonth from n where n.i between 0 and 6 ),
          tbl2 as  (select n.i , dateadd(day,n.i, dateadd(month, datediff(month,0,getdate()),0)) daysOfMonth from n where n.i between datepart(day,dateadd(day,7,(select max(daysOfMonth) from tbl1))) and dateadd(day,7,datepart(day,dateadd(day,6,(select max(daysOfMonth) from tbl1))))),
          tbl3 as  (select n.i  , dateadd(day,n.i, dateadd(month, datediff(month,0,getdate()),0)) daysOfMonth from n where n.i between datepart(day,dateadd(day,7,(select max(daysOfMonth) from tbl2))) and dateadd(day,-1,datepart(day,eomonth(getdate()))))
    select * from tbl1
    union all
    select * from tbl2
    union all
    select * from tbl3

在上面的查询中,CTE表t0, t1 and n用于生成数字。 表tbl将获取该月的前7天。 表tbl2将在接下来的7天中跳过,并在下周获取。这可以使用datediffdateadd函数来完成。 表tbl3将再次跳过7天,并将所有日期拉到月底。

输出

enter image description here

答案 2 :(得分:0)

删除-取消注释选择语句, 我已经打印了结果,您也可以选择。

DECLARE @StartDate datetime ='01-Apr-2019',
        @EndDate datetime ='30-Apr-2019',
        @Interval int = 2


DECLARE @dt datetime = @StartDate,
        @count int = 1

WHILE (@dt <= @EndDate)
BEGIN
    print @dt
    --Select @dt

    IF @count % 7 = 0
    BEGIN
        SET @Interval = @Interval - 1
        SET @dt = dateAdd(day, 8, @dt);
        PRINT '** Skip 7 days'
        --SELECT '** Skip 7 days'
    END 
    ELSE
    BEGIN
        SET @dt = dateAdd(day, 1, @dt);
    END 

    SET @count = @count + 1
END

答案 3 :(得分:0)

使用上一个问题中提供的功能

示例

Declare @Date1 date = '2018-04-01'
Declare @Date2 date = '2018-04-30'
Declare @Freq  int  =  2
Declare @OffDays varchar(50) = 'Thursday'  -- Try 'Saturday,Sunday'


Select B.RetVal
 From  [dbo].[tvf-Range-Date](@Date1,@Date2,'WK',1) A 
 Cross Apply [dbo].[tvf-Range-Date](A.RetVal,DateAdd(DAY,6,A.RetVal),'DD',1) B
 Where A.RetSeq % @Freq = 1
   and B.RetVal<=@Date2

返回

enter image description here

感兴趣的功能

CREATE FUNCTION [dbo].[tvf-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].[tvf-Range-Date]('2016-10-01','2020-10-01','YY',1) 
Select * from [dbo].[tvf-Range-Date]('2016-01-01','2017-01-01','MM',1) 
*/