Zahid Ashiq
Zahid Ashiq

Reputation: 21

Calculate Date list every one week using SQL Server

Looking to fill a table (SQL Server) on the basis of given data:

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

Skip complete one week on the basis of interval. Like shown expected result.

Output:

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

Upvotes: 0

Views: 84

Answers (4)

Rima
Rima

Reputation: 1455

Achieved this using 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

In above query the CTE table t0, t1 and n are used to generste numbers. Table tbl will fetch the first 7 days of the month. Table tbl2 will skip the next 7 days and will fetch next week. this is done using datediff and dateadd function. Table tbl3 will again skip 7 days and will pull all dates till the end of the month.

Output

enter image description here

Upvotes: 1

John Cappelletti
John Cappelletti

Reputation: 81930

With the function provided in your previous question

Example

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

Returns

enter image description here

The Function if Interested

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) 
*/

Upvotes: 0

Hasan Mahmood
Hasan Mahmood

Reputation: 978

remove -- to un-comment select statement, I have printed the result, you can select as well.

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

Upvotes: 0

Luis Cazares
Luis Cazares

Reputation: 3585

This is very simple using a tally table starting with zero.

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;

This of course can be converted into an inline table-valued function to combine performance and ease of use.

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;

Upvotes: 2

Related Questions