how to generate a table of Monday dates that from a specific Monday to current date in sql - sql

In SQL Server I need to generate a table of Mondays up to the current date.
The starting date is always 2020-04-27, which is a Monday.
For example, if today is 2020-05-25, I need a table like below:
date
0 2020-04-27
1 2020-05-04
2 2020-05-11
3 2019-05-18
4 2019-05-25
If today's date is 2020-05-23, then it's:
date
0 2020-04-27
1 2020-05-04
2 2020-05-11
3 2019-05-18
How I can produce the table like that?

You can use a recursive CTE to generate the list of dates:
WITH mondays AS (
SELECT CAST('2020-04-27' AS date) AS monday
UNION ALL
SELECT DATEADD(WEEK, 1, monday)
FROM mondays
WHERE DATEADD(WEEK, 1, monday) <= GETDATE()
)
SELECT *
FROM mondays
Output:
monday
2020-04-27
2020-05-04
2020-05-11
2020-05-18
Demo on dbfiddle
Note that if you want to generate a list of more than 100 dates, you will need to increase the maximum recursion level (which defaults to 100). This can be done by adding OPTION (MAXRECURSION 0) to the end of the query i.e.
SELECT *
FROM mondays
OPTION (MAXRECURSION 0)

Use master..spt_values this default table to attain this
DECLARE #DATEFROM DATE ='2020-04-27',
#DATETO DATE= '2020-05-25'
SELECT ALLDATES AS MONDATES FROM
(SELECT DATEADD(D, NUMBER, #DATEFROM) AS ALLDATES FROM MASTER..SPT_VALUES
WHERE TYPE = 'P' AND NUMBER BETWEEN 0 AND DATEDIFF(DD, #DATEFROM, #DATETO)) AS D1
WHERE DATENAME(DW, D1.ALLDATES)IN('MONDAY')

Related

How to Convert a Date Span to Monthly Records using SQL

I have multiple date spans for the user over a period of few months, I would like to split each span to multiple rows by month and year(default to first day of the month) for which user has been active during the span period. Active user will have future end date records to be split up until the current month and year
Existing Data
ID
Start date
end date
1234
2019-01-01
2019-03-31
1234
2019-09-18
2020-01-31
1234
2022-11-15
2025-01-31
Tried to place the below date month query into the spans
Select Top 500 mmdd=cast (dateadd(Month,-1+Row_Number() Over (Order By (Select NULL)),'2019-01-01') as date)
From master..spt_values n1
order by 1 asc
EXPECTED OUTPUT
ID
active month
1234
2019-01-01
1234
2019-02-01
1234
2019-03-01
1234
2019-09-01
1234
2019-10-01
1234
2019-11-01
1234
2019-12-01
1234
2020-01-01
1234
2022-11-01
1234
2022-12-01
1234
2023-01-01
Larnu is on the right track. One of the easiest ways I've found is to create a calendar table or a function (which can effectively do the same thing).
Try this:
CREATE FUNCTION [dbo].[udfCalendar]
(
#StartDate Date,
#EndDate Date
)
RETURNS #Calendar TABLE (ID int, DateValue DateTime, DayValue int, MonthValue int, YearValue int)
AS
BEGIN
WHILE #StartDate < #EndDate
BEGIN
INSERT #Calendar
SELECT --like 20190101, 1/1/2019, 1, 1, 2019
YEAR (#StartDate) * 10000 + MONTH (#StartDate) * 100 + Day (#StartDate) AS ID,
#StartDate AS DateValue,
DATEPART (dd, #StartDate) AS DayValue,
DATEPART (mm, #StartDate) AS MonthValue,
DATEPART (yy, #StartDate) AS YearValue;
SET #StartDate = DateAdd(m, 1, #StartDate);
END
RETURN;
END
Then you can join to it
Select n1.ID, cal.DateValue as ActiveMonth
From master..spt_values n1 inner join
dbo.udfCalendar('1/1/2019', '1/1/2023') cal
On cal.DateValue Between n1.StartDate and n1.EndDate
Order By DateValue

How to run different date ranges for different months in SQL

I have a requirement to automate dates for a report. The user runs the report four times a year.
Q1-jan-march- run may1
Q2-Apr-Jun - run Aug1
Q3-July-Sep - run Oct1
Q4-oct-dec - run feb1
when the user runs the query in May he should get the result for SELECT * FROM Table where DATE Between jan1 and march31. How do I write different date ranges according to the month it is being run.
Thanks In advance.
You seem to want to filter on the previous quarter. Here is one way to do it:
select *
from mytable
where date >= dateadd(qq, datediff(qq, 0, getdate()) - 1, 0)
and date < dateadd(qq, datediff(qq, 0, getdate()), 0)
This dynamically computes the beginning and end of the previous quarter based on the current date.
If the query subtracts 2 months from the current month, then the functions to determine the beginning and end of the quarter will always return the correct date range. Something like this
with example_run_dates as (
select cast(v.dt as date) dt
from (values ('20200501'), ('20200531'), ('20200801'), ('20200831'),
('20201001'), ('20201031'), ('20210201'), ('20210228')) v(dt))
select cast(dateadd(qq, datediff(qq, 0, mos.two_ago), 0) as date) start_dt,
cast(dateadd(qq, datediff(qq, 0, mos.two_ago)+1, -1) as date) end_dt
from example_run_dates erd
cross apply (select dateadd(month, -2, erd.dt) two_ago) mos;
Output
start_dt end_dt
2020-01-01 2020-03-31
2020-01-01 2020-03-31
2020-04-01 2020-06-30
2020-04-01 2020-06-30
2020-07-01 2020-09-30
2020-07-01 2020-09-30
2020-10-01 2020-12-31
2020-10-01 2020-12-31
DECLARE #FromDate NVARCHAR(255), #ToDate NVARCHAR(255)
SET #FromDate = CASE
WHEN MONTH(GETDATE()) = 5 THEN '20200101'
WHEN MONTH(GETDATE()) = 8 THEN '20200401'
WHEN MONTH(GETDATE()) = 10 THEN CONCAT(YEAR(GETDATE()),'0701')
WHEN MONTH(GETDATE()) = 2 THEN '20201001'
END
SET #ToDate = CASE
WHEN MONTH(GETDATE()) = 5 THEN '20200330'
WHEN MONTH(GETDATE()) = 8 THEN '20200630'
WHEN MONTH(GETDATE()) = 10 THEN CONCAT(YEAR(GETDATE()),'0930')
WHEN MONTH(GETDATE()) = 2 THEN '20201230' END
select #FromDate, #ToDate

Finding all dates after a date for a variable number of days

I have a list of dates in a table. For this examples the 1st day of each month. Let's call it table timeperiod with column endTime
endTime
1-1-2019
2-1-2019
3-1-2019
4-1-2019
I want to find all dates x number of days after each date in a list. Lets say x = 4. Then the list should be:
1-1-2019
1-2-2019
1-3-2019
1-4-2019
2-1-2019
2-2-2019
2-3-2019
2-4-2019
3-1-2019
3-2-2019
3-3-2019
3-4-2019
4-1-2019
4-2-2019
4-3-2019
4-4-2019
I have found solutions to find all dates between dates but I keep getting "Subquery returned more than 1 value" error when I try to use it with a list of dates.
Here is an example of something I tried but doesn't work
declare #days DECIMAL = 4
declare #StartDate date = (select convert(varchar, DATEADD(Day, +0, endTime),101) from timeperiod
declare #EndDate date = (select convert(varchar, DATEADD(Day, +#days, endTime),101) from timeperiod;
;WITH cte AS (
SELECT #StartDate AS myDate
UNION ALL
SELECT DATEADD(day,1,myDate) as myDate
FROM cte
WHERE DATEADD(day,1,myDate) <= #EndDate
)
SELECT myDate
FROM cte
OPTION (MAXRECURSION 0)
Here is a row generator that generates 5 rows, 0 to 4:
WITH rg AS (
SELECT 0 AS rn
UNION ALL
SELECT rg.rn + 1
FROM rg
WHERE rn < 4
)
Here we join it with your existing table that has firsts of the month and use DATEADD to add rn numbers of days (between 0 and 4) to the endPeriod. CROSS JOINing it caused the rows in timePeriod to repeat 5 times each:
SELECT
DATEADD(DAY, rg.rn, timePeriod.endTime) as fakeEndTime
FROM
rg CROSS JOIN timePeriod
I wasn't really clear when you say "days X days after the date, say x = 4" - to me if there is a day that is 1-Jan-2000, then the date 4 days after this is 5-Jan-2000
If you only want the 1,2,3 and 4 of Jan make the row generator < 3 instead of < 4
Already +1'd on Caius Jard's recursive cte.
Here is yet another option using an ad-hoc tally table in concert with a CROSS JOIN
Example
Declare #YourTable Table ([endTime] date)
Insert Into #YourTable Values
('1-1-2019')
,('2-1-2019')
,('3-1-2019')
,('4-1-2019')
Select NewDate = dateadd(DAY,N-1,EndTime)
From #YourTable A
Cross Join (
Select Top (4) N=row_number() over (order by (select null))
From master..spt_values N1
) B
Returns
NewDate
2019-01-01
2019-01-02
2019-01-03
2019-01-04
2019-02-01
2019-02-02
2019-02-03
2019-02-04
2019-03-01
2019-03-02
2019-03-03
2019-03-04
2019-04-01
2019-04-02
2019-04-03
2019-04-04

SQL - creating a list of custom dates between two dates

I am having trouble compiling a query than can do the following:
I have a table which has a startDate and endDate [tblPayments]
I have a column which stores a specific paymentDay [tblPayments]
Data
paymentID startDate endDate paymentDay
1 2016-01-01 2016-12-31 25
2 2015-06-01 2016-06-30 16
I am trying to generate a SELECT query which will split this specific table into separate lines based on the amount of months between these two dates, and set the paymentDay as the day for these queries
Example Output
paymentID expectedDate
1 2016-01-25
1 2016-02-25
1 2016-03-25
1 2016-04-25
1 2016-05-25
1 2016-06-25
1 2016-07-25
1 2016-08-25
1 2016-09-25
1 2016-10-25
1 2016-11-25
1 2016-12-25
2 2015-06-16
2 2015-07-16
2 2015-08-16
2 2015-09-16
2 2015-10-16
2 2015-11-16
2 2015-12-16
2 2016-01-16
2 2016-02-16
2 2016-03-16
2 2016-04-16
2 2016-05-16
I have found a query which will select the months between these dates but its adapting it to my table above, and multiple startDates and endDates I am struggling with
spliting the months
declare #start DATE = '2015-01-01'
declare #end DATE = '2015-12-31'
;with months (date)
AS
(
SELECT #start
UNION ALL
SELECT DATEADD(MM,1,date)
from months
where DATEADD(MM,1,date)<=#end
)
select Datename(MM,date) from months
This query is limited to just one startDate and endDate, so I haven't expanded it to change the DAY of the date.
Use a date table and a simple inner join
DECLARE #tblPayments table (paymentID int identity(1,1), startDate date, endDate date, paymentDay int)
INSERT #tblPayments VALUES
('2016-01-01', '2016-12-31', 25),
('2015-06-01', '2016-06-30', 16)
;WITH dates AS -- Build date within the range of startDate and endDate
(
SELECT MIN(startDate) AS Value, MAX(endDate) AS MaxDate FROM #tblPayments
UNION ALL
SELECT DATEADD(DAY, 1, Value), MaxDate
FROM dates WHERE DATEADD(DAY, 1, Value) <= MaxDate
)
SELECT pay.paymentID, dates.Value AS expectedDate
FROM
#tblPayments pay
INNER JOIN dates ON
dates.Value BETWEEN pay.startDate AND pay.endDate
AND DAY(dates.Value) = paymentDay
OPTION (maxrecursion 0)
I would create an in memory calendar table and then perform a simple query by joining to that:
-- Create a table with all the dates between the min and max dates in the
-- data table
DECLARE #Calendar TABLE
(
[CalendarDate] DATETIME
)
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SELECT #StartDate = MIN(startdate), #EndDate = MAX(enddate) FROM YourDataTable
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO #Calendar (CalendarDate)
SELECT #StartDate
SET #StartDate = DATEADD(dd, 1, #StartDate)
END
-- Join to return only dates between the start and end date that match the Payment Day
SELECT D.PaymentId, C.CalendarDate FROM YourDataTable D
INNER JOIN #Calendar C ON C.CalendarDate BETWEEN D.StartDate AND D.EndDate
AND DATEPART(day, C.CalendarDate) = D.PaymentDay

SQL query : Sum a column (not the date column) for day, week to date, month to date, etc

I am wondering if there is a way within one SQL statement if you can break out a sum of a total column by date, week to date, month to date, etc.
Sample data
DataDate TimeInterval TotalCalls
9/1/2014 12:00 154
9/1/2014 15:15 25
9/2/2014 07:30 125
9/3/2014 11:45 8
9/8/2014 10:15 15
9/9/2014 19:30 6
9/9/2014 12:15 100
In this case, I would want the select statement to return the following data for a given date of 9/9/2014 and week starting on Monday, 9/8/2014
Time Interval SumofCalls
Today 106
WTD 121
MTD 433
I have thought a CASE WHEN would work, but I can only find examples of how to use a CASE WHEN to sum the count of the date column being queried against the criteria. Any suggestions? Thanks!
Here's a way to do it in SQL Server using UNION and getting each range.
SQL Fiddle Demo
DECLARE #today DATE = CAST(GETDATE() AS DATE)
SELECT 'Today' AS 'TimeInterval',
SUM(TotalCalls) AS 'SumOfCalls'
FROM yourTable
WHERE DataDate = #today
UNION ALL
SELECT 'WTD',
SUM(TotalCalls)
FROM yourTable
WHERE DataDate BETWEEN dateadd(week, datediff(week, 0, #today), 0) AND #today
UNION ALL
SELECT 'MTD',
SUM(TotalCalls)
FROM yourTable
WHERE DataDate BETWEEN DATEADD(dd,-(DAY(#today)-1),#today) AND #today
If you could have the times periods go across the top as columns instead of rows then you could use CASE.