Is there a way to specify a date (2020-01-20) and then return every 2 weeks forward and backwards between a start and finish period. So 01 Jan 2020 to 01 Mar 2020 for example. A list of of all the dates every 2 weeks from this input date.
Sample of table data for reference...
DECLARE #Source TABLE(bookingcode int, NextWeekCommDate DATETIME, Cycle int)
insert into #Source (bookingcode, NextWeekCommDate, cycle)
select 556789, '23 Mar 2020', 2
insert into #Source (bookingcode, NextWeekCommDate, cycle)
select 556790, '30 Mar 2020', 3
select * from #Source
declare #from datetime = '01 Mar 2020'
declare #to datetime = '01 Jun 2020'
Then I am trying to output the following results based on the declared#to and #from dates
bookingcode CycleOccurDate
556789 2020-03-09 00:00:00.000
556789 2020-03-23 00:00:00.000
556789 2020-04-06 00:00:00.000
556789 2020-04-20 00:00:00.000
556789 2020-05-04 00:00:00.000
556789 2020-05-18 00:00:00.000
556790 2020-03-30 00:00:00.000
556790 2020-04-20 00:00:00.000
556790 2020-05-11 00:00:00.000
So it works backwards as well from the NextWeekCommDate if the #from date is before this Thank you again
You can use a recursive CTE:
with dates as (
select convert(date, '2020-01-01') as dte
union all
select dateadd(week, 2, dte)
from cte
where dte < '2020-03-01'
)
select *
from dates;
If this can return more than 100 rows, then use option (maxrecursion 0).
It is not clear to me what '2020-01-20' has to do with the question.
Sure, you can add directly or substract fom a date field
SELECT GETDATE(), GETDATE()-14, GETDATE()+14
or in date
SELECT CAST(GETDATE() AS DATE), CAST(GETDATE()-14 AS DATE), CAST(GETDATE()+14 AS DATE)
Take a look at DATE FUNCTIONS in SQLSERVER, there are plenty of them that you may use
https://learn.microsoft.com/es-es/sql/t-sql/functions/date-and-time-data-types-and-functions-transact-sql?view=sql-server-ver15
My question is similar to this
Get a list of dates between two dates using a function
using this code for 10 days recurring:
Declare #startDate datetime
Declare #endDate datetime
set #startDate= '03/01/2019 12:00:00'
set #endDate = '04/30/2019 12:00:00'
;WITH mycte AS
(
SELECT CAST(#startDate AS DATETIME) DateValue
UNION ALL
SELECT DateValue + 10
FROM mycte
WHERE DateValue + 10 < #endDate - 1
)
SELECT DateValue
FROM mycte
OPTION (MAXRECURSION 0)
I get the ff result:
2019-03-20 12:00:00.000
2019-03-30 12:00:00.000
2019-04-09 12:00:00.000
2019-04-19 12:00:00.000
but I want the result to be :
2019-03-20 12:00:00.000
2019-03-30 12:00:00.000
2019-03-31 12:00:00.000
2019-04-09 12:00:00.000
2019-04-10 12:00:00.000
2019-04-20 12:00:00.000
2019-04-21 12:00:00.000
2019-04-30 12:00:00.000
Is this possible with SQL?
I find the problem rather arcane, but this seems to do what you want:
set #startDate= '2019-03-10 12:00:00';
set #endDate = '2019-04-30 12:00:00';
WITH mycte AS (
SELECT CAST(#startDate AS DATETIME) as DateValue
UNION ALL
SELECT CONVERT(DATETIME, EOMONTH(DateValue)) + CONVERT(DATETIME, CONVERT(TIME, DateValue))
FROM mycte
WHERE MONTH(DateValue + 10) <> MONTH(DateValue) AND
CONVERT(DATE, DATEVALUE) <> CONVERT(DATE, EOMONTH(DateValue)) AND
DateValue < #endDate
UNION ALL
SELECT DateValue + 10
FROM mycte
WHERE DateValue + 10 < #endDate
)
SELECT DISTINCT DateValue
FROM mycte
ORDER BY DateValue
OPTION (MAXRECURSION 0);
Here is a db<>fiddle.
I have a Dates CTE that allows me to fill in the dates between date stamped records. (Thanks SO!) However, I need the CTE_Dates table to time stamp its "StatusDate" column with a specific time instead of '00:00:00.000' and am not quite sure how to go about ding so. Here is the CTE_Dates code:
DECLARE #StartDate date = '07/15/2017'
DECLARE #EndDate date = '07/30/2017'
;WITH cte_Dates AS
(
SELECT
CASE WHEN DATEPART(DAY, #StartDate) = 1 THEN #StartDate ELSE DATEADD(Day, DATEDIFF(Day, 1, #StartDate) + 1, 0) END AS StatusDate
UNION ALL
SELECT DATEADD(Day, 1,StatusDate)
FROM cte_Dates
WHERE DATEADD(Day, 1, StatusDate) <= #EndDate
)
--this select statement actually pulls data from 2 CTE's that are joined but represents how I am pulling the StatusDate from CTE_Dates
select
CASE WHEN CAST(statusDate as Date) IS NULL
THEN LAG(cast(StatusDate as Date)) OVER (PARTITION BY item_no ORDER BY statStart)
ELSE StatusDate END as StatusDate,
SELECT * from cte_dates
Results:
StatusDate
2017-07-15 00:00:00.000
2017-07-16 00:00:00.000
2017-07-17 00:00:00.000
2017-07-18 00:00:00.000
2017-07-19 00:00:00.000
2017-07-20 00:00:00.000
2017-07-21 00:00:00.000
2017-07-22 00:00:00.000
2017-07-23 00:00:00.000
2017-07-24 00:00:00.000
2017-07-25 00:00:00.000
2017-07-26 00:00:00.000
2017-07-27 00:00:00.000
2017-07-28 00:00:00.000
2017-07-29 00:00:00.000
2017-07-30 00:00:00.000
The CTE works great! Except I need the timestamp to be noon...
Just add time value to date like this.
DECLARE #StartDate date = '07/15/2017'
DECLARE #EndDate date = '07/30/2017'
;WITH cte_Dates AS
(
SELECT
CASE WHEN DATEPART(DAY, #StartDate) = 1 THEN #StartDate ELSE DATEADD(Day, DATEDIFF(Day, 1, #StartDate) + 1, 0) END
+ '12:00'
AS StatusDate
UNION ALL
SELECT DATEADD(Day, 1,StatusDate)
FROM cte_Dates
WHERE DATEADD(Day, 1, StatusDate) <= #EndDate
)
SELECT * FROM CTE_Dates
You could use dateadd, adding 12 hours:
SELECT DATEADD(HOUR, 12, StatusDate) AS StatusDate FROM CTE_Dates
I would just use two CTEs:
DECLARE #StartDate date = '2017-07-15';
DECLARE #EndDate date = '2017-07-30';
DECLARE #time time = '04:00:00';
WITH cte_Dates AS (
SELECT CASE WHEN DATEPART(DAY, #StartDate) = 1 THEN #StartDate ELSE DATEADD(Day, DATEDIFF(Day, 1, #StartDate) + 1, 0) END AS StatusDate
UNION ALL
SELECT DATEADD(Day, 1,StatusDate)
FROM cte_Dates
WHERE DATEADD(Day, 1, StatusDate) <= #EndDate
),
cte_DateTimes as (
select cast(statusDate as datetime) + cast(#time as datetime)
from cte_Dates
)
SELECT *
FROM CTE_DateTimes;
How can i get the First Date and Last Date between selected months?
For example I Enter year 2015, and month 09 to 2016 08
The return values must be:
StartDate EndDate
20150901 20150930
20151001 20151031
20151101 20151130
20151201 20151231
20160101 20160131
20160201 20160229
20160301 20160331
20160401 20160430
20160501 20160531
20160601 20160630
20160701 20160731
20160801 20160831
I've found multiple queries that do the same but just for 1 inserted date. for example:
DECLARE #mydate DATETIME
SELECT #mydate = GETDATE()
SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(#mydate)-1),#mydate),101) AS Date_Value,
'First Day of Current Month' AS Date_Type
UNION
SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,#mydate))),DATEADD(mm,1,#mydate)),101) ,
'Last Day of Current Month'
But I couldn't find one that can do this for Between statement
I have two udf's which can be used independently or in conjunction. They dynamically create date ranges with variable dateparts and/or increments.
Select * from [dbo].[udf-Create-Range-Date-Span]('2015-09-01','2016-08-01','MM',1)
DateR1 DateR2
2015-09-01 00:00:00.000 2015-10-01 00:00:00.000
2015-10-01 00:00:00.000 2015-11-01 00:00:00.000
2015-11-01 00:00:00.000 2015-12-01 00:00:00.000
2015-12-01 00:00:00.000 2016-01-01 00:00:00.000
2016-01-01 00:00:00.000 2016-02-01 00:00:00.000
2016-02-01 00:00:00.000 2016-03-01 00:00:00.000
2016-03-01 00:00:00.000 2016-04-01 00:00:00.000
2016-04-01 00:00:00.000 2016-05-01 00:00:00.000
2016-05-01 00:00:00.000 2016-06-01 00:00:00.000
2016-06-01 00:00:00.000 2016-07-01 00:00:00.000
2016-07-01 00:00:00.000 2016-08-01 00:00:00.000
Now, I specifically use the cap so I can query data (including time) which are between the DateR1 and DateR2 and
However, with a little twist, you can change the output. For example:
Select DateR1=cast(DateR1 as Date),DateR2=DateAdd(DD,-1,cast(DateR2 as Date)) from [dbo].[udf-Create-Range-Date-Span]('2015-09-01','2016-08-01','MM',1)
DateR1 DateR2
2015-09-01 2015-09-30
2015-10-01 2015-10-31
2015-11-01 2015-11-30
2015-12-01 2015-12-31
2016-01-01 2016-01-31
2016-02-01 2016-02-29
2016-03-01 2016-03-31
2016-04-01 2016-04-30
2016-05-01 2016-05-31
2016-06-01 2016-06-30
2016-07-01 2016-07-31
The two function are as follows:
CREATE FUNCTION [dbo].[udf-Create-Range-Date] (#DateFrom datetime,#DateTo datetime,#DatePart varchar(10),#Incr int)
Returns
#ReturnVal Table (RetVal datetime)
As
Begin
With DateTable As (
Select DateFrom = #DateFrom
Union All
Select Case #DatePart
When 'YY' then DateAdd(YY, #Incr, df.dateFrom)
When 'QQ' then DateAdd(QQ, #Incr, df.dateFrom)
When 'MM' then DateAdd(MM, #Incr, df.dateFrom)
When 'WK' then DateAdd(WK, #Incr, df.dateFrom)
When 'DD' then DateAdd(DD, #Incr, df.dateFrom)
When 'HH' then DateAdd(HH, #Incr, df.dateFrom)
When 'MI' then DateAdd(MI, #Incr, df.dateFrom)
When 'SS' then DateAdd(SS, #Incr, df.dateFrom)
End
From DateTable DF
Where DF.DateFrom < #DateTo
)
Insert into #ReturnVal(RetVal) Select DateFrom From DateTable option (maxrecursion 32767)
Return
End
AND
CREATE FUNCTION [dbo].[udf-Create-Range-Date-Span] (#Date1 datetime,#Date2 datetime,#DatePart varchar(10),#Incr int)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2020-10-01','YY',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-01-01','2016-12-31','MM',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2016-10-31','MI',15)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2016-10-02','SS',1)
Returns Table
As
Return (
Select DateR1 = RetVal
,DateR2 = LEAD(RetVal,1,#Date2) OVER (ORDER BY RetVal)
From (Select * from [dbo].[udf-Create-Range-Date](#Date1,#Date2,#DatePart,#Incr) ) A
Where RetVal<#Date2
)
You don't need UDFs for this - You can do this with a single query:
Declare #FromYear Int = 2015,
#FromMonth Int = 9,
#ToYear Int = 2016,
#ToMonth Int = 8
Declare #FromDate Date = (Select DateAdd(Year, #FromYear - 1900, DateAdd(Month, #FromMonth - 1, 0))),
#ToDate Date = (Select DateAdd(Year, #ToYear - 1900, DateAdd(Month, #ToMonth - 1, 0)))
;With Date (Date) As
(
Select #FromDate Union All
Select DateAdd(Month, 1, Date)
From Date
Where Date < #ToDate
)
Select Convert(Varchar, Year(Date)) + Right('00' + Convert(Varchar, Month(Date)), 2) + Right('00' + Convert(Varchar, Day(Date)), 2) As StartDate,
Convert(Varchar, Year(Date)) + Right('00' + Convert(Varchar, Month(Date)), 2) + Right('00' + Convert(Varchar, Day(DateAdd(Day, -1, DateAdd(Month, DateDiff(Month, 0, Date) + 1, 0)))), 2) As EndDate
From Date
Option (MaxRecursion 0)
Output
StartDate EndDate
20150901 20150930
20151001 20151031
20151101 20151130
20151201 20151231
20160101 20160131
20160201 20160229
20160301 20160331
20160401 20160430
20160501 20160531
20160601 20160630
20160701 20160731
20160801 20160831
If you're able to move to SQL Server 2012 or later, however, the query is much simpler:
Declare #FromYear Int = 2015,
#FromMonth Int = 9,
#ToYear Int = 2016,
#ToMonth Int = 8
Declare #FromDate Date = DateFromParts(#FromYear, #FromMonth, 1),
#ToDate Date = DateFromParts(#ToYear, #ToMonth, 1)
;With Date (Date) As
(
Select #FromDate Union All
Select DateAdd(Month, 1, Date)
From Date
Where Date < #ToDate
)
Select Format(Date, N'yyyyMMdd') As StartDate,
Format(EoMonth(Date), N'yyyyMMdd') As EndDate
From Date
Option (MaxRecursion 0)
Try this. Its also a very small script. I like the idea of the CTE from Siyual. But this is much shorter.
DECLARE #inputYear INT = 2015,
#inputMonth INT = 09
SELECT DATEADD(MONTH, #inputMonth-1, DATEADD(YEAR, #inputYear-1900, 0)) AS FirstDayOfTheMonth,
DATEADD(s,-1, DATEADD(MONTH, #inputMonth, DATEADD(YEAR, #inputYear-1900, 0))) AS LastDayOfTheMonth
Your task is also possible using one single ANSI sql statement.
However, you need two tables ALL_YEARS and ALL_MONTHS that contain the used set of years and month.
E.g. if you consider possible years between 1900 and 2099, the table ALL_YEARS must contain the numbers between 1900 and 2099.
The table ALL_MONTHS must contain the numbers between 1 and 12.
Using these two tables, the statement looks as follows:
select to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy') first_day ,
add_months(to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy'), 1) -1 last_day
from all_years,
all_months
where to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy') between
to_date('01.02.2014', 'dd.mm.yyyy') and
to_date('01.07.2016', 'dd.mm.yyyy');
The output is as follows:
01.02.14 28.02.14
01.03.14 31.03.14
01.04.14 30.04.14
01.05.14 31.05.14
01.06.14 30.06.14
...
01.06.16 30.06.16
01.07.16 31.07.16
I have a table with two columns
start_date 03/09/2016
end_date 03/15/2016
Now I need all the week start and end dates between these two dates
week_start_date week_end_date
03/07/2016 03/11/2016
03/14/2016 03/18/2016
How can I achieve this using sql query. No procedures or t-sql please.
first you have to find all dates between #start_date and #end_date :
declare #start_date datetime
declare #end_date datetime
set #start_date='03/09/2016'
set #end_date='03/15/2016'
;
WITH dates AS (
SELECT #start_date AS dt
UNION ALL
SELECT DATEADD(dd, 1, dt)
FROM dates s
WHERE DATEADD(dd, 1, dt) <= #end_date)
result:
2016-03-09 00:00:00.000
2016-03-10 00:00:00.000
2016-03-11 00:00:00.000
2016-03-12 00:00:00.000
2016-03-13 00:00:00.000
2016-03-14 00:00:00.000
2016-03-15 00:00:00.000
second you need to find out weekday ,'2' is Monday week_start_date
'6' is friday week_end_date
select DATEPART(dw,'03/11/2016') -- friday =6
select DATEPART(dw,'03/14/2016') --- monday =2
here is the final query:
declare #start_date datetime
declare #end_date datetime
set #start_date='03/01/2016'
set #end_date='03/31/2016'
;
WITH sample AS (
SELECT #start_date AS dt
UNION ALL
SELECT DATEADD(dd, 1, dt)
FROM sample s
WHERE DATEADD(dd, 1, dt) <= #end_date)
, dayofWeekTemp as(
SELECT Cast(DATEPART(dw,s.dt) as int) dayOfWeekValue , s.dt dateValue
FROM sample s)
select Case when dayOfWeekValue =6 then 'End of week' when dayOfWeekValue=2 then 'Start of week' End,dateValue from dayofWeekTemp
where dayOfWeekValue=2 Or dayOfWeekValue=6
Results
End of week 2016-03-04 00:00:00.000
Start of week 2016-03-07 00:00:00.000
End of week 2016-03-11 00:00:00.000
Start of week 2016-03-14 00:00:00.000
End of week 2016-03-18 00:00:00.000
Start of week 2016-03-21 00:00:00.000
End of week 2016-03-25 00:00:00.000
Start of week 2016-03-28 00:00:00.000