I need to calculate using SQL Query, how many days within a given range fall into each calendar month.
I have given 2 dates, which define a date range; for example 2020-01-01 to 2020-08-03. I need to find how many days in that range fall in to each month i.e. how many fall into July, and how many into August.
In the example given, the expected result is 31 days in July and 3 days in August.
One approach uses a recusive query. Using date artithmetics, we can build the query so it performs one iteration per month rather than one per day, so this should be a rather efficient approach:
with cte as (
select
datefromparts(year(#dt_start), month(#dt_start), 1) month_start,
1 - day(#dt_start) + day(
case when #dt_end > eomonth(#dt_start)
then eomonth(#dt_start)
else #dt_end
end
) as no_days
union all
select
dateadd(month, 1, month_start),
case when #dt_end > dateadd(month, 2, month_start)
then day(eomonth(dateadd(month, 1, month_start)))
else day(#dt_end)
end
from cte
where dateadd(month, 1, month_start) <= #dt_end
)
select * from cte
Demo on DB Fiddle.
If we set the boundaries as follows:
declare #dt_start date = '2020-07-10';
declare #dt_end date = '2020-09-10';
Then the query returns:
month_start | no_days
:---------- | ------:
2020-07-01 | 22
2020-08-01 | 31
2020-09-01 | 10
You can refer this
;with dates(thedate) as (
select dateadd(yy,years.number,0)+days.number
from master..spt_values years
join master..spt_values days
on days.type='p' and days.number < datepart(dy,dateadd(yy,years.number+1,0)-1)
where years.type='p' and years.number between 100 and 150
-- note: 100-150 creates dates in the year range 2000-2050
-- adjust as required
)
select dateadd(m,datediff(m, 0, d.thedate),0) themonth, count(1)
from dates d
where d.thedate between '2020-01-01' and '2020-08-03'
group by datediff(m, 0, d.thedate)
order by themonth;
Please refer the link below where RichardTheKiwi user given a clear example for your scenario.
SQL Server query for total number of days for a month between date ranges
You can do all the work at the month level rather than the day level -- which should be a bit faster. Here is a method using a recursive CTE:
with cte as (
select #startdate as startdate, #enddate as enddate,
datefromparts(year(#startdate), month(#startdate), 1) as month
union all
select startdate, enddate, dateadd(month, 1, month)
from cte
where dateadd(month, 1, month) < #enddate
)
select month,
(case when month <= startdate and dateadd(month, 1, month) >= enddate
then day(enddate) - day(startdate) + 1
when month <= startdate
then day(eomonth(month)) - day(startdate) + 1
when dateadd(month, 1, month) < enddate
then day(eomonth(month))
when dateadd(month, 1, month) >= enddate
then day(enddate)
end)
from cte;
And the db<>fiddle.
The logic is simpler at the day level:
with cte as (
select #startdate as dte, #enddate as enddate
union all
select dateadd(day, 1, dte), enddate
from cte
where dte < enddate
)
select datefromparts(year(dte), month(dte), 1) as yyyymm, count(*)
from cte
group by datefromparts(year(dte), month(dte), 1)
order by yyyymm
option (maxrecursion 0)
Here is a solution with recursive CTE.
declare #startDate date = '2020-07-01'
declare #endDate date = '2020-08-03'
; WITH cte (n, year, month, daycnt)
AS (
SELECT
0
, DATEPART(year, #startDate)
, DATENAME(MONTH, #startDate)
, DATEPART(day, EOMONTH( #startDate ) ) - DATEPART(day, #startDate ) + 1
UNION ALL
SELECT
n + 1
, DATEPART(year, DATEADD(month, n + 1, #startDate) )
, DATENAME(MONTH, DATEADD(month, n + 1, #startDate) )
, IIF(
n = ( DATEPART(month, #endDate) - DATEPART(month, #startDate) ) + ( DATEPART(year, #endDate) - DATEPART(year, #startDate) ) * 12 - 1
, DATEPART(day, #endDate )
, DATEPART(day, EOMONTH( DATEADD(month, n + 1, #startDate) ) )
)
FROM
cte
WHERE
n <= ( DATEPART(month, #endDate) - DATEPART(month, #startDate) ) + ( DATEPART(year, #endDate) - DATEPART(year, #startDate) ) * 12 - 1
)
SELECT *
FROM cte
ORDER BY n
OPTION (maxrecursion 0)
This could be further simplified with a number function but that would also be essentially be a recursive CTE, though it would definitely look cleaner. But it requires defining a function on top of this SELECT statement.
My goal to is get get query that will return weekdays in a month. I can get the days of the month but I need to get dates starting from monday through Friday even if the Monday may be in the preceding month.
Example April 1st is a wednesday so I would need to bring back March 30th and 31st. And the last date returned would be by May 1st as that is the last friday that contains some April days..
If interested in a helper function, I have TVF which generates a calendar.
Example
Select * from [dbo].[tvf-Date-Calendar-Wide]('2020-04-01')
Returns
So, with a little tweak, we get can
Select WeekNr = RowNr
,B.*
From [dbo].[tvf-Date-Calendar-Wide]('2020-04-01') A
Cross Apply ( values (Mon)
,(Tue)
,(Wed)
,(Thu)
,(Fri)
) B(Date)
Which Returns
WeekNr Date
1 2020-03-30
1 2020-03-31
1 2020-04-01
1 2020-04-02
1 2020-04-03
2 2020-04-06
2 2020-04-07
2 2020-04-08
...
5 2020-04-29
5 2020-04-30
5 2020-05-01
The Function If Interested
CREATE FUNCTION [dbo].[tvf-Date-Calendar-Wide] (#Date1 Date)
Returns Table
Return (
Select RowNr,[Sun],[Mon],[Tue],[Wed],[Thu],[Fri],[Sat]
From (
Select D
,DOW=left(datename(WEEKDAY,d),3)
,RowNr = sum(Flg) over (order by D)
From (
Select D,Flg=case when datename(WEEKDAY,d)= 'Sunday' then 1 else 0 end
From (Select Top (42) D=DateAdd(DAY,-7+Row_Number() Over (Order By (Select Null)),#Date1) From master..spt_values n1 ) A
) A
) src
Pivot (max(d) for DOW in ([Sun],[Mon],[Tue],[Wed],[Thu],[Fri],[Sat]) )pvg
Where [Sun] is not null
and [Sat] is not null
)
-- Select * from [dbo].[tvf-Date-Calendar-Wide]('2020-04-01')
You first need to find the start of the week for the first day of the month, then the date for the end of the week that contains the last day of the month:
e.g.
SELECT WeekStart = DATEADD(DAY, -(DATEPART(WEEKDAY, '20200401')-1), '20200401'),
WeekEnd = DATEADD(DAY, 7-(DATEPART(WEEKDAY, '20200430')), '20200430');
Gives:
WeekStart WeekEnd
------------------------------
2020-03-29 2020-05-02
You wouldn't want to hard code the first and the last of the month, but these are fairly trivial things to get from a date:
DECLARE #Date DATE = '20200415';
SELECT MonthStart = DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0),
MonthEnd = EOMONTH(#Date);
Which returns
MonthStart MonthEnd
------------------------------
2020-04-01 2020-04-30
You can then just substitute this into the first query for week starts:
DECLARE #Date DATE = '20200401';
SELECT WeekStart = DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0))-1), DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0)),
WeekEnd = DATEADD(DAY, 7-(DATEPART(WEEKDAY, EOMONTH(#Date))), EOMONTH(#Date));
Which gives the same output as the first query with hard coded dates. This is very clunky though, so I would separate this out into a further step:
DECLARE #Date DATE = '20200401';
-- SET DATE TO THE FIRST OF THE MONTH IN CASE IT IS NOT ALREADY
SET #Date = DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0);
SELECT WeekStart = DATEADD(DAY, -(DATEPART(WEEKDAY, #Date)-1), #Date),
Weekend = DATEADD(DAY, 7-(DATEPART(WEEKDAY, EOMONTH(#Date))), EOMONTH(#Date));
Again, this gives the same output (2020-03-29 & 2020-05-02).
The next step is to fill in all the dates between that are weekdays. If you have a calendar table this is very simple
DECLARE #Date DATE = '20200415';
-- SET DATE TO THE FIRST OF THE MONTH IN CASE IT IS NOT ALREADY
SET #Date = DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0);
DECLARE #Start DATE = DATEADD(DAY, -(DATEPART(WEEKDAY, #Date)-1), #Date),
#End DATE = DATEADD(DAY, 7-(DATEPART(WEEKDAY, EOMONTH(#Date))), EOMONTH(#Date));
SELECT [Date], DayName = DATENAME(WEEKDAY, [Date])
FROM Calendar
WHERE Date >= #Start
AND Date <= #End
AND IsWeekday = 1
ORDER BY [Date];
If you don't have a calendar table, then I suggest you create one, but if you can't create one you can still generate this on the fly, by generating a set series numbers and adding these numbers to your start date:
DECLARE #Date DATE = '20200415';
-- SET DATE TO THE FIRST OF THE MONTH IN CASE IT IS NOT ALREADY
SET #Date = DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0);
DECLARE #Start DATE = DATEADD(DAY, -(DATEPART(WEEKDAY, #Date)-1), #Date),
#End DATE = DATEADD(DAY, 7-(DATEPART(WEEKDAY, EOMONTH(#Date))), EOMONTH(#Date));
-- GET NUMBERS FROM 0 - 50
WITH Dates (Date) AS
( SELECT TOP (DATEDIFF(DAY, #Start, #End))
DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY n1.n) - 1, #Start)
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n1 (n)
CROSS JOIN (VALUES (1),(1),(1),(1),(1)) n2 (n)
)
SELECT [Date], DayName = DATENAME(WEEKDAY, [Date])
FROM Dates
WHERE ((DATEPART(WEEKDAY, [Date]) + ##DATEFIRST) % 7) NOT IN (0, 1);
Just generate all possible dates -- up to 6 days before the month begins. Take the valid weekdays after the first Monday:
with dates as (
select dateadd(day, -6, convert(date, '2020-04-01')) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < '2020-04-30'
)
select dte
from (select d.*,
min(case when datename(weekday, dte) = 'Monday' then dte end) over () as first_monday
from dates d
) d
where datename(weekday, dte) not in ('Saturday', 'Sunday') and
dte >= first_monday;
declare #dateVal datetime = GETDATE(); --assign your date here
declare #monthFirstDate datetime = cast(YEAR(#dateVal) as varchar(4)) + '-' + DATENAME(mm, #dateVal) + '-' + cast(01 as varchar(2))
declare #monthLastDate datetime = DAteADD(day, -1, DATEADD(month, 1, cast(YEAR(#dateVal) as varchar(4)) + '-' + DATENAME(mm, #dateVal) + '-' + cast(01 as varchar(2))))
declare #startDate datetime = DATEADD(DAY, 2 - DATEPART(WEEKDAY, #monthFirstDate), CAST(#monthFirstDate AS DATE))
declare #enddate datetime = DATEADD(DAY, 6 - DATEPART(WEEKDAY, #monthLastDate), CAST(#monthLastDate AS DATE))
Select #startDate StartDate, #enddate EndDate
****Result**
--------------------------------------------------------------
StartDate | EndDate
-----------------------------|--------------------------------
2020-03-02 00:00:00.000 | 2020-04-03 00:00:00.000
-----------------------------|---------------------------------**
I am using the below query to find the count from a table based on a date for the last 5-6 weeks as below
BEGIN
SET datefirst 1;
DECLARE #BeginDate datetime= '2016-10-10'
SELECT
count(*) as Total
, datepart(wk, DateCreated) as WeekNumber
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
FROM TABLESES
WHERE
CONVERT(date,DateCreated) >= DATEADD(DAY, -42, #BeginDate)
AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, #BeginDate)
GROUP BY datepart(wk, DateCreated)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
ORDER BY datepart(wk, DateCreated)
END
This will return a result set like below:
Total WeekNumber WeekStartDate WeekEndDate
51295 36 29.08.2016 04.09.2016
48133 37 05.09.2016 11.09.2016
38991 38 12.09.2016 18.09.2016
38074 39 19.09.2016 25.09.2016
37192 40 26.09.2016 02.10.2016
20835 41 03.10.2016 09.10.2016
23781 42 10.10.2016 16.10.2016
Now I want to add one more column in the end with count for the same week number in last year.
Can I achieve the same in this query itself? Or should I write a totally different query for it? And how can I make this query?
You can use UNION with DATEDIFF to get the same thing for the previous year:
SELECT
count(*) as Total
, datepart(wk, DateCreated) as WeekNumber
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
FROM TABLESES
WHERE
CONVERT(date,DateCreated) >= DATEADD(DAY, -42, #BeginDate)
AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, #BeginDate)
GROUP BY datepart(wk, DateCreated)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
UNION ALL
SELECT
count(*) as Total
, datepart(wk, DATEDIFF(year,1,DateCreated )) as WeekNumber
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,0),104) as WeekStartDate
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,6),104) as WeekEndDate
FROM TABLESES
WHERE
CONVERT(date,DateCreated) >= DATEADD(DAY, -42, #BeginDate)
AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, #BeginDate)
GROUP BY datepart(wk, DATEDIFF(year,1,DateCreated ))
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,0),104)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DATEDIFF(year,1,DateCreated ))/7,6),104)
ORDER BY datepart(wk, DATEDIFF(year,1,DateCreated ))
Put your end-result to a temp table and then do something like this:
Be sure to check your date logic with previous year. But hope you get the logic. I havent tested if your "Version" is correct as i have wroted, but i hope you get the picture.
Result with test version
TEST Version:
DECLARE #Weeks1 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50)
)
DECLARE #Weeks2 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50)
)
insert into #Weeks1 (Total,Weeknumber,WeekStartDate,Weekenddate)
values ('51295', '36' ,'29.08.2016' ,'04.09.2016'),
('48133', '37' ,'05.09.2016' ,'11.09.2016'),
('38991', '38' ,'12.09.2016' ,'18.09.2016'),
('38074', '39' ,'19.09.2016' ,'25.09.2016'),
('37192', '40' ,'26.09.2016' ,'02.10.2016'),
('20835', '41' ,'03.10.2016' ,'09.10.2016'),
('23781', '42' ,'10.10.2016' ,'16.10.2016')
insert into #Weeks2 (Total,Weeknumber,WeekStartDate,Weekenddate)
values ('324234', '36' ,'29.08.2015' ,'04.09.2015'),
('22333', '37' ,'05.09.2015' ,'11.09.2015'),
('23444', '38' ,'12.09.2015' ,'18.09.2015'),
('566666', '39' ,'19.09.2015' ,'25.09.2015'),
('4345', '40' ,'26.09.2015' ,'02.10.2015'),
('8657', '41' ,'03.10.2015' ,'09.10.2015'),
('8567567', '42' ,'10.10.2015' ,'16.10.2015')
Select a.Total,b.Total as
LastYearTotal,a.Weeknumber,A.WeekStartDate,a.Weekenddate from #Weeks1 a
inner join #Weeks2 b on a.Weeknumber = b.Weeknumber
With your version:
DECLARE #Weeks1 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50)
)
DECLARE #Weeks2 TABLE(
Total int,
Weeknumber INT,
WeekStartDate nvarchar(50),
WeekEndDate nvarchar(50)
)
BEGIN
SET datefirst 1;
DECLARE #BeginDate datetime= '2016-10-10'
insert into #Weeks1 (Total,Weeknumber,WeekStartDate,Weekenddate)
SELECT
count(*) as Total
, datepart(wk, DateCreated) as WeekNumber
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
FROM TABLESES
WHERE
CONVERT(date,DateCreated) >= DATEADD(DAY, -42, #BeginDate)
AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, #BeginDate)
GROUP BY datepart(wk, DateCreated)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
ORDER BY datepart(wk, DateCreated)
END
BEGIN
SET datefirst 1;
DECLARE #BeginDate2 datetime= '2015-10-10'
insert into #Weeks2 (Total,Weeknumber,WeekStartDate,Weekenddate)
SELECT
count(*) as Total
, datepart(wk, DateCreated) as WeekNumber
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
FROM TABLESES
WHERE
CONVERT(date,DateCreated) >= DATEADD(DAY, -42, #BeginDate2)
AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, #BeginDate2)
GROUP BY datepart(wk, DateCreated)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
ORDER BY datepart(wk, DateCreated)
END
Select a.Total,b.Total as
LastYearTotal,a.Weeknumber,A.WeekStartDate,a.Weekenddate from #Weeks1 a
inner join #Weeks2 b on a.Weeknumber = b.Weeknumber
If only weeks matter you can make some date calculations first and have a simpler query
SET datefirst 1;
DECLARE #BeginDate datetime = '2016-10-10'; -- must be start of the week , <= last week -6
declare #nweeks int = 6;
-- this year interval
declare #b1Date datetime = dateadd(week, -#nweeks , #BeginDate); --inclusive
declare #e1Date datetime = dateadd(week, 1 , #BeginDate); -- exclusive
declare #thisYear int = datepart(year, #b1Date);
-- previous year interval
declare #bwk int = datepart(week, #b1Date);
declare #year2 datetime= dateadd(year,datediff(year,0,#b1Date)-1,0);
declare #b2Date datetime = dateadd(week, #bwk-1, #year2);
declare #e2Date datetime = dateadd(week, #bwk + #nweeks, #year2);
-- check it
select #BeginDate, #b1Date, #e1Date, #bwk, #b2Date, #e2Date, datepart(week, #b2Date);
SELECT
count(case datepart(year, DateCreated) when #thisYear then 1 end) as TotalThisYear
, datepart(wk, DateCreated) as WeekNumber
, convert(VARCHAR(20),dateadd(week,datepart(week,DateCreated)-#bwk -1,#b1Date),104) as WeekStartDate
, convert(VARCHAR(20),dateadd(day,7*(datepart(week,DateCreated)-#bwk-1)+6,#b1Date),104) as WeekEndDate
, count(case datepart(year, DateCreated) when #thisYear-1 then 1 end) as TotalPrev
FROM TABLESES
WHERE
CONVERT(date,DateCreated) >= #b1Date AND CONVERT(date,DateCreated) <#e1Date
OR
CONVERT(date,DateCreated) >= #b2Date AND CONVERT(date,DateCreated) <#e2Date
GROUP BY datepart(wk, DateCreated)
ORDER BY datepart(wk, DateCreated)
Yes, you can use your same query but with few modifications. I have used 2 CTE's , one for your query and another for prior year weeks. Then join both on the weeknumber to fetch the needed last column as you can see below.
BEGIN
SET datefirst 1;
DECLARE #BeginDate datetime= '2016-10-10'
;WITH CTE1 as
SELECT
count(*) as Total
, datepart(wk, DateCreated) as WeekNumber
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104) as WeekStartDate
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104) as WeekEndDate
FROM TABLESES
WHERE
CONVERT(date,DateCreated) >= DATEADD(DAY, -42, #BeginDate)
AND CONVERT(date,DateCreated) <= DATEADD(DAY, 6, #BeginDate)
GROUP BY datepart(wk, DateCreated)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,0),104)
, convert(VARCHAR(20),dateadd(week,datediff(day,0,DateCreated )/7,6),104)
,CTE2 as
SELECT count(*) as Total
,datepart(wk, dateadd(year, -1, DateCreated)) as WeekNumber
FROM TABLESES
GROUP BY datepart(wk, dateadd(year, -1, DateCreated))
SELECT CTE1.*, CTE2.Total
FROM CTE1 JOIN CTE2
ON CTE1.WeekNumber = CTE2.WeekNumber
END
I am almost a newbie to writing SQL queries.
In the context of SQL Server, how to get list of 2nd and 4th Saturday dates
in the year 2016?
Done as a derived table simply to show the logic but you can reduce if you prefer:
select *
from (
select d2016,
datename( weekday, d2016 ) as wkdy,
row_number( ) over ( partition by datepart( month, d2016 ), datename( weekday, d2016 ) order by d2016 ) as rn_dy_mth
from (
select dateadd( day, rn, cast( '2016-01-01' as date ) ) as d2016
from (
select row_number() over( order by object_id ) - 1 as rn
from sys.columns
) as rn
) as dy
) as dy_mth
where rn_dy_mth in ( 2, 4 )
and wkdy = 'Saturday'
order by d2016
--DEFINE LIMITS FOR DAY
DECLARE #TODATE DATETIME, #FROMDATE DATETIME
SET #FROMDATE ='2010-01-01'
SET #TODATE = '2017-12-31'
;WITH DATESEQUENCE( [DATE] ) AS
(
SELECT #FROMDATE AS [DATE]
UNION ALL
SELECT DATEADD(DAY, 1, [DATE])
FROM DATESEQUENCE
WHERE DATE < #TODATE
)
, DATESATURDAY AS
(SELECT CAST(CAST(YEAR([DATE]) AS VARCHAR)+
(CASE WHEN DATEPART(M,[DATE])<=9 THEN '0'+CAST(DATEPART(M,[DATE]) AS VARCHAR)
ELSE CAST(DATEPART(M,[DATE]) AS VARCHAR) END ) AS NUMERIC) AS MONTH_ID
,CONVERT(VARCHAR,[DATE],106) AS DAY_DESC
,UPPER(DATENAME(DW,[DATE]))AS DAY_NAME
FROM DATESEQUENCE )
,SECOND_FOURTH_SATURDAY AS
(SELECT *
,ROW_NUMBER() OVER (PARTITION BY MONTH_ID ORDER BY DAY_NAME) FALL_IN
FROM DATESATURDAY
WHERE DAY_NAME='SATURDAY')
SELECT * FROM SECOND_FOURTH_SATURDAY
WHERE FALL_IN IN(2,4)
OPTION (MAXRECURSION 10000)
You can get any Saturday of a month using the Following Query in SQL.
Here I'm Getting on Current Date, You can set your own selected date to get a Specific month Saturday
select DATEADD(dd, (14 - ##DATEFIRST - DATEPART(dw, DATEADD(MONTH, DATEDIFF(mm, 0,getdate()), 0))) % 7, DATEADD(MONTH, DATEDIFF(mm, 0, getdate()), 0)) as FirstSaturday,
DATEADD(dd,7,DATEADD(dd, (14 - ##DATEFIRST - DATEPART(dw, DATEADD(MONTH, DATEDIFF(mm, 0, getdate()), 0))) % 7, DATEADD(MONTH, DATEDIFF(mm, 0, getdate()), 0))) as SecondSaturday,
DATEADD(dd,14,DATEADD(dd, (14 - ##DATEFIRST - DATEPART(dw, DATEADD(MONTH, DATEDIFF(mm, 0, getdate()), 0))) % 7, DATEADD(MONTH, DATEDIFF(mm, 0, getdate()), 0))) as ThirdSaturday,
DATEADD(dd,21,DATEADD(dd, (14 - ##DATEFIRST - DATEPART(dw, DATEADD(MONTH, DATEDIFF(mm, 0, getdate()), 0))) % 7, DATEADD(MONTH, DATEDIFF(mm, 0, getdate()), 0))) as LastSaturday