I am trying to find attendance for any month like this:
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SET #StartDate = '2016/10/01'
SET #EndDate = '2016/10/31'
SELECT
StaffAttendance.StaffId, DATENAME(MONTH, #StartDate) AS [ForMonth],
(DATEDIFF(dd, #StartDate, #EndDate) + 1)
-(DATEDIFF(wk, #StartDate, #EndDate) * 1)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END) AS TotalWorkingDays,
SUM(StaffAttendance.AttendanceStatusId) AS TotalDaysWorked FROM StaffAttendance WHERE [Date] BETWEEN #StartDate AND #EndDate AND StaffAttendance.AttendanceStatusId = 1 GROUP BY StaffAttendance.StaffId
And this is what I am getting, which is just fine.
What I want to do next is omit the date range (#StartDate DATE, #EndDate DATE) and use month name instead like - 'October' and not month number like '10.' So that user gives a month name and start and end dates for that month are automatically calculated. I got help for that by Felix Pamittan.
DECLARE #month VARCHAR(9) = 'february';
WITH CteMonths(n, m) AS(
SELECT 1, 'January' UNION ALL
SELECT 2, 'February' UNION ALL
SELECT 3, 'March' UNION ALL
SELECT 4, 'April' UNION ALL
SELECT 5, 'May' UNION ALL
SELECT 6, 'June' UNION ALL
SELECT 7, 'July' UNION ALL
SELECT 8, 'August' UNION ALL
SELECT 9, 'September' UNION ALL
SELECT 10, 'October' UNION ALL
SELECT 11, 'November' UNION ALL
SELECT 12, 'December'
)
SELECT
DATEADD(MONTH, n - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)) AS StartDate,
DATEADD(DAY, -1, DATEADD(MONTH, n, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0))) AS EndDate
FROM CteMonths
WHERE m = #month
Now, how do I combine these two and get same result as above?
Use CROSS APPLY:
DECLARE #month VARCHAR(9) = 'february';
WITH CteMonths(n, m) AS(
SELECT 1, 'January' UNION ALL
SELECT 2, 'February' UNION ALL
SELECT 3, 'March' UNION ALL
SELECT 4, 'April' UNION ALL
SELECT 5, 'May' UNION ALL
SELECT 6, 'June' UNION ALL
SELECT 7, 'July' UNION ALL
SELECT 8, 'August' UNION ALL
SELECT 9, 'September' UNION ALL
SELECT 10, 'October' UNION ALL
SELECT 11, 'November' UNION ALL
SELECT 12, 'December'
)
SELECT
sa.StaffId,
DATENAME(MONTH, t.StartDate) AS [ForMonth],
(DATEDIFF(dd, t.StartDate, t.EndDate) + 1)
- (DATEDIFF(wk, t.StartDate, t.EndDate) * 1)
- (CASE WHEN DATENAME(dw, t.StartDate) = 'Sunday' THEN 1 ELSE 0 END) AS TotalWorkingDays,
SUM(sa.AttendanceStatusId) AS TotalDaysWorked
FROM StaffAttendance sa
CROSS APPLY(
SELECT
DATEADD(MONTH, n - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)) AS StartDate,
DATEADD(DAY, -1, DATEADD(MONTH, n, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0))) AS EndDate
FROM CteMonths
) t
WHERE
sa.[Date] >= t.StartDate
AND sa.[Date] < DATEADD(DAY, 1, t.EndDate)
AND sa.AttendanceStatusId = 1
GROUP BY sa.StaffId
Related
I want to create a Calendar Table without using the recursion as I have prepared earlier. How can I achieve this task. All the required columns are mentioned in code below and few other details in code comments.
...........................................................................................................................................................................................................................................................................
DECLARE #StartDate date = '20200101'
DECLARE #CutoffDate date = GETDATE()
;WITH seq(n) AS
(
SELECT 0 UNION ALL SELECT n + 1 FROM seq
WHERE n < DATEDIFF(DAY, #StartDate, #CutoffDate)
),
d(d) AS
(
SELECT DATEADD(DAY, n, #StartDate) FROM seq
),
src AS /*SOURCE TABLE WITH OBJECT DEFINITION*/
(
SELECT
TheDate = CONVERT(date, d),
TheDay = DATEPART(DAY, d),
TheDayName = DATENAME(WEEKDAY, d),
TheWeek = DATEPART(WEEK, d),
TheDayOfWeek = DATEPART(WEEKDAY, d),
TheMonth = DATEPART(MONTH, d),
TheMonthName = DATENAME(MONTH, d),
TheQuarter = Concat('Q',DATEPART(Quarter, d)),
Financial_Year = DATEPART(YEAR, d),
Financial_Quarter=Datepart(QUARTER,d),
TheYear = DATEPART(YEAR, d),
TheFirstOfMonth = DATEFROMPARTS(YEAR(d), MONTH(d), 1),
TheFirstOfFYear = DATEFROMPARTS(YEAR(d), 4, 1),
TheFirstOfYear = DATEFROMPARTS(YEAR(d), 1, 1),
TheLastOfYear = DATEFROMPARTS(YEAR(d), 12, 31),
TheDayOfYear = DATEPART(DAYOFYEAR, d)
FROM d
),
Dimension AS
(
SELECT
TheDate,
TheDay,
TheDayName,
TheDayOfWeek,
TheDayOfWeekInMonth = CONVERT(tinyint, ROW_NUMBER() OVER
(PARTITION BY TheFirstOfMonth, TheDayOfWeek ORDER BY TheDate)),
TheDayOfYear,
TheWeek,
TheFirstOfWeek = DATEADD(DAY, 1 - TheDayOfWeek, TheDate),
TheLastOfWeek = DATEADD(DAY, 6, DATEADD(DAY, 1 - TheDayOfWeek, TheDate)),
TheWeekOfMonth = CONVERT(tinyint, DENSE_RANK() OVER
(PARTITION BY TheYear, TheMonth ORDER BY TheWeek)),
TheMonth,
TheMonthName,
TheFirstOfMonth,
TheLastOfMonth = MAX(TheDate) OVER (PARTITION BY TheYear, TheMonth),
TheFirstOfNextMonth = DATEADD(MONTH, 1, TheFirstOfMonth),
TheLastOfNextMonth = DATEADD(DAY, -1, DATEADD(MONTH, 2, TheFirstOfMonth)),
TheQuarter,
TheFirstOfQuarter = MIN(TheDate) OVER (PARTITION BY TheYear, TheQuarter),
TheLastOfQuarter = MAX(TheDate) OVER (PARTITION BY TheYear, TheQuarter),
TheYear,
TheFirstOfYear = DATEFROMPARTS(TheYear, 1, 1),
TheFirstOfFYear = DATEFROMPARTS(TheYear, 4, 1),
TheLastOfYear,
MMYYYY = CONVERT(char(2), CONVERT(char(8), TheDate, 101))
+ CONVERT(char(4), TheYear),
Financial_Quarter = Datepart(Quarter,DATEADD(MONTH, -3, TheFirstOfMonth)), /*Starting Financial Quarter from April*/
Financial_Year =CASE
WHEN Financial_Quarter = 1 THEN DATEPART(Year,Dateadd(Year,-1,TheFirstofYear)) ELSE THEYEAR END
FROM src
)
SELECT * FROM Dimension
ORDER BY TheDate
OPTION (MAXRECURSION 0);
As I mentioned in the comments, use a Tally. These are significantly faster than a rCTE as they aren't recursive. I use an inline tally here:
DECLARE #StartDate date = '20200101';
DECLARE #CutoffDate date = GETDATE();
/*
; is a terminator, not a "beginingator". It goes at the end of ALL your statements,
not at the start of statements that require the PREVIOUS statement to be properly terminated.
*/
WITH N AS
(SELECT N
FROM (VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS
(SELECT 0 AS I
UNION ALL
SELECT TOP (DATEDIFF(DAY, #StartDate, #CutoffDate))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1,N N2,N N3), --Up to 1000 rows. Add more cross joins for more rows
D AS
(SELECT DATEADD(DAY, T.I, #StartDate) AS d
FROM Tally T),
Src AS /*SOURCE TABLE WITH OBJECT DEFINITION*/
(SELECT CONVERT(date, d) AS TheDate,
DATEPART(DAY, d) AS TheDay,
DATENAME(WEEKDAY, d) AS TheDayName,
DATEPART(WEEK, d) AS TheWeek,
DATEPART(WEEKDAY, d) AS TheDayOfWeek,
DATEPART(MONTH, d) AS TheMonth,
DATENAME(MONTH, d) AS TheMonthName,
CONCAT('Q', DATEPART(QUARTER, d)) AS TheQuarter,
DATEPART(YEAR, d) AS Financial_Year,
DATEPART(QUARTER, d) AS Financial_Quarter,
DATEPART(YEAR, d) AS TheYear,
DATEFROMPARTS(YEAR(d), MONTH(d), 1) AS TheFirstOfMonth,
DATEFROMPARTS(YEAR(d), 4, 1) AS TheFirstOfFYear,
DATEFROMPARTS(YEAR(d), 1, 1) AS TheFirstOfYear,
DATEFROMPARTS(YEAR(d), 12, 31) AS TheLastOfYear,
DATEPART(DAYOFYEAR, d) AS TheDayOfYear
FROM d),
Dimension AS
(SELECT TheDate,
TheDay,
TheDayName,
TheDayOfWeek,
CONVERT(tinyint, ROW_NUMBER() OVER (PARTITION BY TheFirstOfMonth, TheDayOfWeek ORDER BY TheDate)) AS TheDayOfWeekInMonth,
TheDayOfYear,
TheWeek,
DATEADD(DAY, 1 - TheDayOfWeek, TheDate) AS TheFirstOfWeek,
DATEADD(DAY, 6, DATEADD(DAY, 1 - TheDayOfWeek, TheDate)) AS TheLastOfWeek,
CONVERT(tinyint, DENSE_RANK() OVER (PARTITION BY TheYear, TheMonth ORDER BY TheWeek)) AS TheWeekOfMonth,
TheMonth,
TheMonthName,
TheFirstOfMonth,
MAX(TheDate) OVER (PARTITION BY TheYear, TheMonth) AS TheLastOfMonth,
DATEADD(MONTH, 1, TheFirstOfMonth) AS TheFirstOfNextMonth,
DATEADD(DAY, -1, DATEADD(MONTH, 2, TheFirstOfMonth)) AS TheLastOfNextMonth,
TheQuarter,
MIN(TheDate) OVER (PARTITION BY TheYear, TheQuarter) AS TheFirstOfQuarter,
MAX(TheDate) OVER (PARTITION BY TheYear, TheQuarter) AS TheLastOfQuarter,
TheYear,
DATEFROMPARTS(TheYear, 1, 1) AS TheFirstOfYear,
DATEFROMPARTS(TheYear, 4, 1) AS TheFirstOfFYear,
TheLastOfYear,
CONVERT(char(2), CONVERT(char(8), TheDate, 101)) + CONVERT(char(4), TheYear) AS MMYYYY,
DATEPART(QUARTER, DATEADD(MONTH, -3, TheFirstOfMonth)) AS Financial_Quarter, /*Starting Financial Quarter from April*/
CASE
WHEN Financial_Quarter = 1 THEN DATEPART(YEAR, DATEADD(YEAR, -1, TheFirstOfYear))
ELSE TheYear
END AS Financial_Year
FROM src)
SELECT *
FROM Dimension
ORDER BY TheDate;
I'm working on a SQL query trying to fetch sum data for the current day/date. Can anyone have a look at my query, and find me a working solution?
SELECT SUM(amount)
FROM tbl_expense_record
WHERE dateonly = CAST(GETDATE() AS Date)
But I get data when mentioning a specific date in where condition like
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly = '2020-06-12'
I want the a code to auto pick current date. Also I would like to fetch sum of ranged dates like a whole week, and a month!
select datename(month, '2020-06-12'), datename(month, getdate());
--1week
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(week, -1, cast(getdate() as date))
and dateonly <= cast(getdate() as date)
--1month
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly <= cast(getdate() as date)
--build muscle memory (it is always safe to check for < date+1 instead of <= date)
--1month
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date));
--6months
SELECT SUM(amount) AS total
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -6, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date));
if not exists
(
select *
FROM tbl_expense_record
WHERE dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date))
)
begin
select 'no rows within the last month'
end
else
begin
select 'there are rows within the last month';
end;
Examples:
declare #tbl_expense_record table(dateonly date, amount decimal(9,2));
insert into #tbl_expense_record
values ('20200501', 10), ('20200612', 10), ('20200613', 11), ('20200614', 12),
('20200710', 5), ('20200720', 6), ('20200820', 20), ('20200825', 30),
('20201102', 1), ('20201110', 2), ('20201120', 3);
--aggregation per month, for all rows
select year(dateonly) as _year, month(dateonly) as _month, sum(amount) as sum_amount_per_month, count(*) as rows_per_month
from #tbl_expense_record
group by year(dateonly), month(dateonly);
--aggregation per iso-week
select year(dateonly) as _year, datepart(iso_week, dateonly) as _isoweek, sum(amount) as sum_amount_per_isoweek, count(*) as rows_per_isoweek
from #tbl_expense_record
group by year(dateonly), datepart(iso_week, dateonly);
--aggregation per month, for all rows with a dateonly that falls in the last month
--check the difference between aggregation per month earlier and this..
--filter rows first == where .... and then aggregate
--there are two rows with dateonly > 06 november (the row at 05 is filtered out by the where clause)
select year(dateonly) as _year, month(dateonly) as _month, sum(amount) as sum_amount_per_month, count(*) as rows_per_month
from #tbl_expense_record
where dateonly >= dateadd(month, -1, cast(getdate() as date))
and dateonly < dateadd(day, 1, cast(getdate() as date))
group by year(dateonly), month(dateonly);
--aggregate per week diff from today/getdate()
select
datediff(week, getdate(), dateonly) as week_diff_from_today,
dateadd(day,
--datepart(weekday..) is used...account for ##datefirst setting / set datefirst
1-(##datefirst+datepart(weekday, dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date))))%7,
dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date)))
as startofweek,
dateadd(day, 6, --add 6 days to startofweek
dateadd(day,
--datepart(weekday..) is used...account for ##datefirst setting / set datefirst
1-(##datefirst+datepart(weekday, dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date))))%7,
dateadd(week, datediff(week, getdate(), dateonly), cast(getdate() as date)))
) as endofweek,
sum(amount) as sum_amount, count(*) as rows_within_week
from #tbl_expense_record
group by datediff(week, getdate(), dateonly);
How do I get start date and end date of a month by month name? Not by date, not by month number.
For example, this gets me first day of current month. Input is a date type, not string like I want it to be.
SELECT DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), 0)
What I want is to input month name in string like 'March' not 3 and get 2016/03/01 and 2016/03/31. I'd really be overwhelmed and appreciate any/all help.
You can create a CTE to get the month number:
DECLARE #month VARCHAR(10) = 'March';
WITH CteMonths(n, m) AS(
SELECT 1, 'January' UNION ALL
SELECT 2, 'February' UNION ALL
SELECT 3, 'March' UNION ALL
SELECT 4, 'April' UNION ALL
SELECT 5, 'May' UNION ALL
SELECT 6, 'June' UNION ALL
SELECT 7, 'July' UNION ALL
SELECT 8, 'August' UNION ALL
SELECT 9, 'September' UNION ALL
SELECT 10, 'October' UNION ALL
SELECT 11, 'November' UNION ALL
SELECT 12, 'December'
)
SELECT
DATEADD(MONTH, n - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)),
DATEADD(DAY, -1, DATEADD(MONTH, n, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)))
FROM CteMonths
WHERE m = #month
This is my stored procedure which I was able to create
CREATE PROCEDURE [dbo].[spGetAllStaffCollectiveAttendanceByMonth]
#Month nvarchar(9)
AS
BEGIN
Declare #StartDate DATE,
#EndDate DATE
;WITH CteMonths(n, m) AS(
SELECT 1, 'January' UNION ALL
SELECT 2, 'February' UNION ALL
SELECT 3, 'March' UNION ALL
SELECT 4, 'April' UNION ALL
SELECT 5, 'May' UNION ALL
SELECT 6, 'June' UNION ALL
SELECT 7, 'July' UNION ALL
SELECT 8, 'August' UNION ALL
SELECT 9, 'September' UNION ALL
SELECT 10, 'October' UNION ALL
SELECT 11, 'November' UNION ALL
SELECT 12, 'December'
)
SELECT #StartDate = DATEADD(MONTH, n - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)),
#EndDate = DATEADD(DAY, -1, DATEADD(MONTH, n, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)))
FROM CteMonths
WHERE m = #month
SELECT
StaffAttendance.StaffId,
DATENAME(MONTH, #StartDate) AS [ForMonth], #StartDate AS StartDate, #EndDate AS EndDate,
(DATEDIFF(dd, #StartDate, #EndDate) + 1)-(DATEDIFF(wk, #StartDate, #EndDate) * 1)-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END) AS TotalWorkingDays,
SUM(StaffAttendance.AttendanceStatusId) AS TotalDaysWorked
FROM StaffAttendance
WHERE [Date] BETWEEN #StartDate AND #EndDate AND StaffAttendance.AttendanceStatusId = 1 GROUP BY StaffAttendance.StaffId
END
GO
This, here, is my function which I am trying to create but can't. Its the same thing as above except for what makes it a function.
CREATE FUNCTION [dbo].[funcGetAllStaffCollectiveAttendanceByMonth]
(
#Month nvarchar(9)
)
RETURNS TABLE
AS
RETURN
(
Declare #StartDate DATE,
#EndDate DATE
;WITH CteMonths(n, m) AS(
SELECT 1, 'January' UNION ALL
SELECT 2, 'February' UNION ALL
SELECT 3, 'March' UNION ALL
SELECT 4, 'April' UNION ALL
SELECT 5, 'May' UNION ALL
SELECT 6, 'June' UNION ALL
SELECT 7, 'July' UNION ALL
SELECT 8, 'August' UNION ALL
SELECT 9, 'September' UNION ALL
SELECT 10, 'October' UNION ALL
SELECT 11, 'November' UNION ALL
SELECT 12, 'December'
)
SELECT #StartDate = DATEADD(MONTH, n - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)),
#EndDate = DATEADD(DAY, -1, DATEADD(MONTH, n, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)))
FROM CteMonths
WHERE m = #month
SELECT
StaffAttendance.StaffId,
DATENAME(MONTH, #StartDate) AS [ForMonth], #StartDate AS StartDate, #EndDate AS EndDate,
(DATEDIFF(dd, #StartDate, #EndDate) + 1)-(DATEDIFF(wk, #StartDate, #EndDate) * 1)-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END) AS TotalWorkingDays,
SUM(StaffAttendance.AttendanceStatusId) AS TotalDaysWorked
FROM StaffAttendance
WHERE [Date] BETWEEN #StartDate AND #EndDate AND StaffAttendance.AttendanceStatusId = 1 GROUP BY StaffAttendance.StaffId
END
)
But this is what I am getting
What am I doing wrong?
You have used the syntax for an inline table-valued function but you have multiple statements.
Comparison of inline and multi-statement table-valued functions.
So you could either refactor to use a single statement (higher performance) or use the multi-statement syntax as described in that link (easier).
If you wanted to do it inline you could do something along these lines (note, I don't have SSMS available right now so there may be some minor syntax errors like unmatched brackets):
CREATE FUNCTION [dbo].[funcGetAllStaffCollectiveAttendanceByMonth]
(
#Month nvarchar(9)
)
RETURNS TABLE
AS
RETURN
(
-- The StartDate should be the first day of the month that is passed as a parameter, in the current year.
-- The EndDate should be the last day of the month which the StartDate begins.
WITH cteDates AS (
SELECT StartDate = Convert(date, Concat('01', #Month, Convert(varchar(4), DatePart(Year, GetDate()))), 106),
EndDate = DateAdd(Day, -1,
DateAdd(Month, 1,
Convert(date, Concat('01', #Month, Convert(varchar(4), DatePart(Year, GetDate()))) , 106)
)
)
)
SELECT
Sa.StaffId,
DATENAME(MONTH, cteDates.StartDate) AS [ForMonth],
cteDates.StartDate,
cteDates.EndDate,
(DATEDIFF(dd, cteDates.StartDate, cteDates.EndDate) + 1)-
(DATEDIFF(wk, cteDates.StartDate, cteDates.EndDate) * 1)-
(CASE WHEN DATENAME(dw, cteDates.StartDate) = 'Sunday' THEN 1 ELSE 0 END) AS TotalWorkingDays,
SUM(sa.AttendanceStatusId) AS TotalDaysWorked
FROM StaffAttendance As sa
JOIN cteDates ON sa.[Date] BETWEEN cteDates.StartDate AND cteDates.EndDate
WHERE sa.AttendanceStatusId = 1
GROUP BY
Sa.StaffId,
DATENAME(MONTH, cteDates.StartDate),
cteDates.StartDate,
cteDates.EndDate,
(DATEDIFF(dd, cteDates.StartDate, cteDates.EndDate) + 1)-
(DATEDIFF(wk, cteDates.StartDate, cteDates.EndDate) * 1)-
(CASE WHEN DATENAME(dw, cteDates.StartDate) = 'Sunday' THEN 1 ELSE 0 END)
END
)
I need to get all week start and end dates(weeks) between two dates and then run a query returning the number of records inserted in each of those weeks.
declare #sDate datetime,
#eDate datetime;
select #sDate = '2013-02-25',
#eDate = '2013-03-25';
--query to get all weeks between sDate and eDate
--query to return number of items inserted in each of the weeks returned
WEEK NoOfItems
-----------------------------------------
2013-02-25 5
2013-03-4 2
2013-03-11 7
You can use a recursive CTE to generate the list of dates:
;with cte as
(
select #sDate StartDate,
DATEADD(wk, DATEDIFF(wk, 0, #sDate), 6) EndDate
union all
select dateadd(ww, 1, StartDate),
dateadd(ww, 1, EndDate)
from cte
where dateadd(ww, 1, StartDate)<= #eDate
)
select *
from cte
See SQL Fiddle with Demo.
Then you can join this to your table, to return the additional details.
Here is my solution. Inspired by this answer
DECLARE #sDate DATE = DATEADD(MONTH, -6, GETDATE())
DECLARE #eDate DATE = GETDATE()
;WITH cte AS
(
SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, #sDate), 0) AS StartDate, DATEADD(WEEK, DATEDIFF(WEEK, 0, #sDate), 6) AS EndDate
UNION ALL
SELECT DATEADD(WEEK, 1, StartDate), DATEADD(WEEK, 1, EndDate)
FROM cte
WHERE DATEADD(WEEK, 1, StartDate) <= #eDate
)
SELECT * FROM cte