How to get max Saturday dates in a column of each month, without hardcoding - sql

How to get max Saturday dates in a column of each month in SQL Server. Can someone please help me.
Now I need only the dates which has last Saturday of month.
For example,
The table has
07-08-2021 - Saturday
14-08-2021 - Saturday
21-08-2021 - Saturday
28-08-2021 - Saturday
04-09-2021 - Saturday
11-09-2021 - Saturday
18-09-2021 - Saturday
25-09-2021 - Saturday
Suppose we are in August month, I need to select last Saturday of that month( ONLY 28-08-2021)
Suppose we are in September month, I need to select last Saturday of that month( ONLY 25-09-2021)
Output:
28-08-2021
25-09-2021

assuming you have a datefield in your table (I will refer to it here as such in the below query)
with week as (
select
date_trunc('week', datefield + interval '2 day') - interval '2 day' as week_date
-- ^this adjusts the week date_trunc to start on Saturday (it starts on Monday by default)
from sometable
)
select
extract(month from week_date) as month_num,
max(week_date) as last_saturday
from week
group by month_num
note: if you only have partial data for the current month, this query will need to be altered slightly, but you didn't give me a lot to go off of here

A CTE is defined to populate the day name of entire month and then the requirement is filtered.
;with GetDates As (
select CAST('01-01-2021' as date) as StartDate, datename(dw, '09-01-2021') as Day_Name
UNION ALL
select DATEADD(day,1, StartDate), datename(dw, DATEADD(day,1, StartDate))
from GetDates
where StartDate < '09-30-2021'
)
select max(StartDate)
from GetDates where Day_Name = 'Saturday'
group by month(StartDate)
OPTION (MAXRECURSION 500)

Here is a function to calculate the Nth Weekday - which can calculate from the beginning of the month or from the end of the month.
Alter Function dbo.fnGetNthWeekDay (
#theDate datetime
, #theWeekday int
, #theNthDay int
)
Returns Table
As
Return
/*
Adapted from a version published by Peter Larrson - with minor modifications for performance
and restructured to eliminate usage of a derived table.
Inputs:
#theDate any date in the month
#theWeekday the weekday to calculate: 1 = Monday
2 = Tuesday
3 = Wednesday
4 = Thursday
5 = Friday
6 = Saturday
7 = Sunday
#theNthDay the week count where positive is from beginning of the month
and negative is from end of month
Outputs:
#theDate the date entered
#theNthDate the Nth date of the month
*/
Select theDate = #theDate
, dt.nthDate
From (Values (dateadd(month, datediff(month, #theNthDay, #theDate), 0))) As mm(FirstOfMonth)
Cross Apply (Values (dateadd(day, 7 * #theNthDay - 7 * sign(#theNthDay + 1)
+ (#theWeekday + 6 - datediff(day, -53690, mm.FirstOfMonth) % 7) % 7, mm.FirstOfMonth))) As dt(nthDate)
Where #theWeekday Between 1 And 7
And datediff(month, dt.nthDate, #theDate) = 0
And #theNthDay In (-5, -4, -3, -2, -1, 1, 2, 3, 4, 5);
Go
You can then call it like this:
Select * From dbo.fnGetNthWeekDay('2021-08-15', 6, -1) nwd

Related

Calculate Quarter Start Date

As I have to calculate Start date of specific quarter and Quarter No from any financial year start date based on #firstMonthOfFiscalyear parameter. Let's say if #firstMonthOfFiscalyear =4 mean my financial year start date is 1 April and my quarter no start as below.
Q1 - April to Jun
Q2 - July to Sep
Q3 - Oct to Dec
Q4 - Jan to March
This quarter no will change based on #firstMonthOfFiscalyear parameter value.
From this I am able to get Quarter number but not able to get Start date of that quarter. So anyone can help me on this.
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
DECLARE #firstMonthOfFiscalyear int = 4 --Finanical year start month
SET #StartDateTime = '2017-04-01'
SET #EndDateTime = '2019-03-31';
WITH DateRange(Dates) AS
(
SELECT #StartDateTime as Date
Union ALL
SELECT DATEADD(d,1,Dates)
FROM DateRange
WHERE Dates < #EndDateTime
)
SELECT Dates
,FLOOR(((12 + MONTH(Dates) - #firstMonthOfFiscalyear) % 12) / 3 ) + 1 as quarterNo
, DATEADD(month, (IIF((month(dates)-#firstMonthOfFiscalyear)<0,(month(dates)-#firstMonthOfFiscalyear)+12,(month(dates)-#firstMonthOfFiscalyear))/3)*3, CAST( DATEFROMPARTS(year(dates),#firstMonthOfFiscalyear ,1) as Datetime)) as QuarterStartDate
FROM DateRange
OPTION (MAXRECURSION 0)
To calculate the fiscal quarter, you can just subtract the month difference and calculate the "real" quarter:
DATEPART(quarter, DATEADD(month, 1-#firstMonthOfFiscalyear, Dates))
To calculate the start of the quarter, calculate the start of the "real" quarter for the date reduced by the month difference and finally add the month difference again. The start of the "real" quarter of a #date can be calculated as follows, making use of the fact that DATEDIFF returns an integer and so the division by 3 is an integer division (do not remove the brackets, the multiplication has to be done after the integer division):
DATEADD(month, 3*(DATEDIFF(month, 0, #date)/3), 0)
Replacing #date with Dates, reduced by #firstMonthOfFiscalyear-1 months and adding #firstMonthOfFiscalyear-1 months in the end, this will be
DATEADD(month, #firstMonthOfFiscalyear-1, DATEADD(month, 3*(DATEDIFF(month, 0, DATEADD(month, 1-#firstMonthOfFiscalyear, Dates))/3), 0))
This can be simplified a little to
DATEADD(month, #firstMonthOfFiscalyear-1 + 3*((DATEDIFF(month, 0, Dates)+1-#firstMonthOfFiscalyear)/3), 0)
So in the end, your query could look like this:
SELECT Dates
, DATEPART(quarter, DATEADD(month, 1-#firstMonthOfFiscalyear, Dates)) AS quarterNo
, DATEADD(month, #firstMonthOfFiscalyear-1 + 3*((DATEDIFF(month, 0, Dates)+1-#firstMonthOfFiscalyear)/3), 0) AS QuarterStartDate
FROM DateRange
Since the start of the year can be found using DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0), just add #firstMonthOfFiscalyear - 1 months:
DATEADD(mm,#firstMonthOfFiscalyear,DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0)
How to get the first and last date of the current year?
Or by building the string:
CAST(CAST(#firstMonthOfFiscalyear AS VARCHAR(2)) + '/1/' CAST(DATEPART(YY,GETDATE()) AS VARCHAR(4)) AS DATE)
You can try this query to get start date of next 4 quarters based on your input. use DATEFROMPARTS function to build start date of first quarter then use CTE to build start date of next quarters by adding 3 months to previous quarter.
DECLARE #firstMonthOfFiscalyear int = 4
;WITH MyQuarters(q, qDate) as
(
select 1,
DATEFROMPARTS(year(getdate()), #firstMonthOfFiscalyear, 1) -- First quarter date
UNION ALL
select q+1,
DATEADD(q, 1, qdate) -- next quarter start date
from MyQuarters
where q <4 -- limiting the number of next quarters
)
select * from MyQuarters
Output:
q qDate
1 2018-04-01
2 2018-07-01
3 2018-10-01
4 2019-01-01

Select week day names for the time interval

I have time interval, and I want my query to output a table with one column Days which is going to have all days of week in that interval in the natural order so if the interval is bigger than a week (i.e. between '2014-2-1' and '2014-2-21'), the result would be:
Day
----
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
If the interval starts, lets say on Friday and ends on the following Monday (i.e. between '2014-2-21' and '2014-2-24'), the output will be:
Day
----
Sunday
Monday
Friday
Saturday
I'd use the following approach:
generate a row for each day in your range (with ROW_NUMBER())
get the weekday for each generated row (using datename(weekday, ..) )
get the numeric weekday (using ##datefirst / datepart)
SQL:
DECLARE #StartDate DATE = '20140221'
, #EndDate DATE = '20140224'
SELECT
datename(weekday, v1.day) as weekday,
(((##datefirst-1) + datepart(weekday, v1.day)) % 7) as weekday_num,
v1.day FROM (
SELECT DATEADD(DAY, nbr - 1, #StartDate) AS day
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
FROM sys.columns c
) nbrs
WHERE nbr - 1 <= DATEDIFF(DAY, #StartDate, #EndDate)
) v1
order by 2
UPDATE
To correctly handle the case with more than 7 days, you can wrap it in another SELECT with DISTINCT:
DECLARE #StartDate DATE = '20140221'
, #EndDate DATE = '20140224'
SELECT DISTINCT weekday, weekday_num FROM (
SELECT
datename(weekday, v1.day) as weekday,
(((##datefirst-1) + datepart(weekday, v1.day)) % 7) as weekday_num,
v1.day FROM (
SELECT DATEADD(DAY, nbr - 1, #StartDate) AS day
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
FROM sys.columns c
) nbrs
WHERE nbr - 1 <= DATEDIFF(DAY, #StartDate, #EndDate)
) v1
) v2 order by 2
SQL Fiddle
You could use a combination of DatePart and DateName to do this. You can get your date like this:
select datename(dw,getdate()) --Friday
select datepart(dw,getdate()) --6
Just substitute getdate() (which would return today's date) with your field name. Then, you can display DateName but sort by DatePart.

Get yesterdays date and if Monday get weekend range for SQL server

How do I get yesterdays date and if the current date is Monday I would need Sunday, Saturday and Friday. This is already asked here for ms access. I now need this for SQL server. How would I go about this?
Will create an inline view that will return the previous date in SQL It will return between 1 and 3 rows depending on the current date.
If current date is Monday Return:
Sundays date
Saturdays date
Fridays date
If current date is Tuesday then Return: Mondays date
If current date is Wednesday then Return: Tuesdays date
If current date is Thursday then Return: Wednesdays date
If current date is Friday then Return: Thursdays date
If current date is Saturday then Return: Fridays date
If current date is Sunday then Return: Saturdays date
I hope this helps explain what I am trying to do more clearly.
sample select query
--get previous date
select * from [Purchase Orders] where MyDate in (previous date(s))
Not entirely clear about the question though. But you can do something on the similar lines.
Using DATEPART and DATEADD
DECLARE #TodaysDate DATETIME
SET #TodaysDate = '2013-04-10'
SELECT CASE
WHEN DATEPART (DW, DATEADD (DD, -1, #TodaysDate )) IN (1, 6, 7)
THEN 'WeekEnd' ELSE 'WeekDay'
END D
Using the query you linked to, you can try the code below:
SELECT *
FROM [Purchase Order]
WHERE MyDate >= CASE
WHEN DATENAME(dw, CONVERT(CHAR(8), GETDATE() , 112)) LIKE 'Monday' THEN CONVERT(CHAR(8), DATEADD(dd, -3, GETDATE()), 112)
ELSE CONVERT(CHAR(8), DATEADD(dd, -1, GETDATE()), 112)
END
AND MyDate < CONVERT(CHAR(8),GETDATE(),112)
You can use the following table function:
CREATE FUNCTION dbo.ufnPreviousDay (#suppliedDate DATE)
RETURNS #PreviousDates TABLE (PreviousDate DATE)
AS
BEGIN
INSERT INTO #PreviousDates (
PreviousDate)
SELECT
PreviousDate = DATEADD(DAY, -1, #suppliedDate)
IF DATEPART(WEEKDAY, DATEADD(DAY, ##DATEFIRST - 1, #suppliedDate)) = 1 -- If Monday
BEGIN
INSERT INTO #PreviousDates (
PreviousDate)
SELECT
PreviousDate = DATEADD(DAY, -2, #suppliedDate)
UNION ALL
SELECT
PreviousDate = DATEADD(DAY, -3, #suppliedDate)
END
RETURN
END
You can use it like this:
SELECT
T.*
FROM
dbo.ufnPreviousDay('2018-03-19') AS T
/*
Result:
2018-03-18
2018-03-17
2018-03-16
*/
If you want today's previous dates:
SELECT
T.*
FROM
YourTable AS T
INNER JOIN dbo.ufnPreviousDay(GETDATE()) AS M ON T.MyDate = M.PreviousDate

Get the most recent Friday's date SQL

I'm trying to get the most recent Friday in SQL Server 2008.
I have this. It gets the beginning of the week (monday) then subtracts 3 days to get Friday.
declare #recentFriday datetime = DATEADD(ww, DATEDIFF(dd,0,GETDATE()), 0)-3
When this is run during the week, it gets last Friday's date which is correct. But when run on Friday (or Saturday), it still gets last week's date instead of the current week's Friday. I'm about to use if/else conditions but I'm sure there's an easier way.
This works for any input and any setting of DATEFIRST:
dateadd(d, -((datepart(weekday, getdate()) + 1 + ##DATEFIRST) % 7), getdate())
It works by adjusting the weekday value so that 0 = Friday, simulating Friday as the beginning of the week. Then subtract the weekday value if non-zero to get the most recent Friday.
Edit: Updated to work for any setting of DATEFIRST.
DECLARE #date DATETIME = '20110512' -- Thursday
SELECT DATEADD(DAY,-(DATEDIFF(DAY,'19000105',#date)%7),#date) --20110506
SET #date = '20110513' -- Friday
SELECT DATEADD(DAY,-(DATEDIFF(DAY,'19000105',#date)%7),#date) --20110513
SET #date = '20110514' -- Saturday
SELECT DATEADD(DAY,-(DATEDIFF(DAY,'19000105',#date)%7),#date) --20110513
Calculate the number of days between a known Friday (05 Jan 1900) and the given date
The remainder left from dividing the difference in 1. by 7 will be the days elapsed since the last Friday
Subtract the remainder in 2. from the given date
you can check if the current day of week is friday or greater DATEPART(dw,GETDATE()) and then call (SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0)+4) or (SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0)-3)
SELECT
CASE WHEN DATEPART(dw,GETDATE()) >= 5 THEN
(SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0)+4)
ELSE
(SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0)-3)
END
Using a known Friday date (I'll use Jan 7, 2011) as a starting point, you can do this:
DECLARE #d DATETIME
SET #d = '2011-05-13' /* Friday */
SELECT DATEADD(DAY, (DATEDIFF (DAY, '20110107', #d) / 7) * 7, '20110107')
/* Returns 2011-05-13 */
SET #d = '2011-05-12' /* Thursday */
SELECT DATEADD(DAY, (DATEDIFF (DAY, '20110107', #d) / 7) * 7, '20110107')
/* Returns 2011-05-06 */
Just choose a known Friday that's older than any dates you'll be using in your calculations.
SELECT CONVERT(VARCHAR(12),GETDATE()) AS Today,
CASE WHEN (DATEPART(DW,GETDATE())< 7)
THEN CONVERT(VARCHAR(12),(DATEADD(dd,-(DATEPART(DW,GETDATE())+1),GETDATE())))
ELSE CONVERT(VARCHAR(12),(DATEADD(d,- 1,GETDATE())))
END AS [Last Friday]
Here is a completly set oriented way to achive the last Friday:
select Friday from
(
select max(GetDate()) as Friday where datepart(dw, getdate()) = 6
union all
select max((GetDate() - 1)) where datepart(dw, (getdate() - 1)) = 6
union all
select max((GetDate() - 2)) where datepart(dw, (getdate() - 2)) = 6
union all
select max((GetDate() - 3)) where datepart(dw, (getdate() - 3)) = 6
union all
select max((GetDate() - 4)) where datepart(dw, (getdate() - 4)) = 6
union all
select max((GetDate() - 5)) where datepart(dw, (getdate() - 5)) = 6
) x where Friday is not null
The other solutions were not working for my use case.
This works for finding any previous day by replacing 'Sunday' with the day you`re looking for:
DECLARE #myDate DATE = GETDATE()
WHILE DATENAME(WEEKDAY, #myDate) <> 'Sunday'
BEGIN
SET #myDate = DATEADD(DAY, -1, #myDate)
END
This is what I got I hope it helps
DECLARE #UserDate DateTime
SET #UserDate = '2020-09-03'
SELECT DATEADD(day, (6 - datepart(weekday, #UserDate)) , #UserDate)

Select rows with date field having values within this week

I am trying to select all the rows from a table where a date field has values within the current week. I want the rows from the current week's Monday until the current day.
Example:
ID adate
---------------
1 11-11-2010
2 12-11-2010
3 13-11-2010
4 14-11-2010
5 15-11-2010
The rows I want in this case are:
ID adate
---------------
4 14-11-2010 //this week's Monday
5 15-11-2010 //till today
This will work on a week from Sunday to Saturday. You shall adapt it if you want weeks from Monday to Sunday:
select *
from myTable
where aDate between
cast('now' as date) - extract(weekday from cast('now' as date)) --prev sunday
and
cast('now' as date) - extract(weekday from cast('now' as date)) + 6 --next saturday
;
I wrote it in ms sql:
declare #today as datetime
declare #first_day_of_week datetime
set #today = convert(varchar, getDate(), 101)
set #first_day_of_week = dateadd(day, -(DATEPART(WEEKDAY, #today) - 1), #today)
select *
from [table]
where adate between #first_day_of_week and #today
Sunday is the beginning of the week.