Datepart week start Monday used in a view - sql

I am trying to use the DATEPART function in my SELECT query that constructs a view.
The aim of the DATEPART is to return the weeknumber of a date passed to it. I require the start of the week to be a Monday and the default, which in my case is a Sunday.
I am not able to use Set DATEFIRST 1 since I want to use the Datepart in a view.
eg. Lets use the date '2021-01-31' as [Date]
DATEPART(WEEK,DATE) --returns week 6 with ##DATEFIRST = 7
DATEPART(WEEK,DATE) --returns week 5 with ##DATEFIRST = 1
All suggestions would highly be appreciated.

I can offer such a solution:
declare
#DATE date='2021-01-31'
select DATEPART(WEEK,#DATE) --returns week 6 with ##DATEFIRST = 7
,DATEPART(WEEK,case when datepart(dw, #DATE)=1 then dateadd(dd, -1, #DATE) else #DATE end) --returns week 5 with ##DATEFIRST = 1

Related

SQL server: Get week number of month with saturday as first day of week [duplicate]

This question already has answers here:
Calculate week of month starting Monday
(2 answers)
Closed 5 years ago.
I'm looking for a sql script to calculate the week number of month with saturday as the first day of the week.
Example:
2017-04-01 : Week 1
2017-04-02 : Week 1
(.................)
2017-04-08 : Week 2
Thanks.
Try this, I think it's all that you need:
set datefirst 6
declare #dt datetime
set #dt = '2017-03-04'
select datepart(wk, #dt) - datepart(wk,dateadd(m, DATEDIFF(M, 0, #dt), 0)) + 1 as weekOfMonth
You could use this query
DECLARE #currentdate date = '2017-04-01'
select floor((datepart(day,#currentdate) - 1)/7) + 1 AS WeekOfMonth
--- #currentdate date = '2017-04-01' -- return 1
--- #currentdate date = '2017-04-07' -- return 1
--- #currentdate date = '2017-04-08' -- return 2
Please make use of below query :
SELECT 'Week '+ CAST(FLOOR((datepart(day,#YourDate) - 1)/7) + 1 AS VARCHAR(10)) Currentweek
You can use DATEFIRST with DATEADD. Setting DATEFIRST to the value 6 represents Saturday.
Try this (replace yourDate with your datetime column):
SET DATEFIRST 6
select datediff(week, dateadd(month, 0, yourDate), yourDate) + 1

For Mondays I need to set default date to previous Friday for App?

When a Report is run on a Monday it needs to set the default date to Friday ? Also 4 other conditions looking at the requirments. How to do this in an sql statement is the question.
So in pseudo code,
If today's date is Monday then set default date to Friday with full date format.
If today's date is Saturday then set default date to Friday with full date format.
If today's date is Sunday then set default date to Friday with full date format.
If any other day , then set default date to previous working day .
So need one sql statement maybe with a case statement .
Now I found these statements which give day of week so now need to do next part which may be a case statement or maybe a function ? This is the part I need assistance pl.
select datename(dw,getdate()) --Monday
select datepart(dw,getdate()) -- 1
SET DATEFIRST 1;
DECLARE #day DATE = SYSDATETIME();
SELECT #day = DATEADD
(
DAY,
CASE
WHEN DATEPART(WEEKDAY, #day) IN (1,2)
THEN -(DATEPART(WEEKDAY, #day)+1)
ELSE -1
END,
#day);
SELECT #day;
So, if the WEEKDAY (or dw) value is 3-6 (Tuesday through Saturday), then subtract one day. Otherwise subtract an additional day for Sunday and an addition two days for Monday.
Fortunately, the value for Sunday is 1 and the value for Monday is 2, so you can just subtract those values for those days.
DECLARE #DefaultDate datetime
SET #DefaultDate =
CASE
WHEN DATEPART(WEEKDAY, GETDATE()) IN (1,2) -- OR (1,7) outside the U.S.
THEN DATEADD(DAY, (-1 - DATEPART(WEEKDAY, GETDATE())), GETDATE())
ELSE
DATEADD(DAY, -1, GETDATE())
END

How to get Previous business day in a week with that of current Business Day using sql server

i have an ssis Package which runs on business days (mon-Fri). if i receive file on tuesday , background(DB), it takes previous business day date and does some transactions. If i run the job on friday, it has to fetch mondays date and process the transactions.
i have used the below query to get previous business date
Select Convert(varchar(50), Position_ID) as Position_ID,
TransAmount_Base,
Insert_Date as InsertDate
from tblsample
Where AsOfdate = Dateadd(dd, -1, Convert(datetime, Convert(varchar(10), '03/28/2012', 101), 120))
Order By Position_ID
if i execute this query i'll get the results of yesterdays Transactios. if i ran the same query on monday, it has to fetch the Fridays transactions instead of Sundays.
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
I prefer to use DATENAME for things like this over DATEPART as it removes the need for Setting DATEFIRST And ensures that variations on time/date settings on local machines do not affect the results. Finally DATEDIFF(DAY, 0, GETDATE()) will remove the time part of GETDATE() removing the need to convert to varchar (much slower).
EDIT (almost 2 years on)
This answer was very early in my SO career and it annoys me everytime it gets upvoted because I no longer agree with the sentiment of using DATENAME.
A much more rubust solution would be:
SELECT DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7
WHEN 1 THEN -2
WHEN 2 THEN -3
ELSE -1
END, DATEDIFF(DAY, 0, GETDATE()));
This will work for all language and DATEFIRST settings.
This function returns last working day and takes into account holidays and weekends. You will need to create a simple holiday table.
-- =============================================
-- Author: Dale Kilian
-- Create date: 2019-04-29
-- Description: recursive function returns last work day for weekends and
-- holidays
-- =============================================
ALTER FUNCTION dbo.fnGetWorkWeekday
(
#theDate DATE
)
RETURNS DATE
AS
BEGIN
DECLARE #importDate DATE = #theDate
DECLARE #returnDate DATE
--Holidays
IF EXISTS(SELECT 1 FROM dbo.Holidays WHERE isDeleted = 0 AND #theDate = Holiday_Date)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Satruday
IF(DATEPART(WEEKDAY,#theDate) = 7)
BEGIN
SET #importDate = DATEADD(DAY,-1,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
--Sunday
IF(DATEPART(WEEKDAY,#theDate) = 1)
BEGIN
SET #importDate = DATEADD(DAY,-2,#theDate);
SET #importDate = (SELECT dbo.fnGetWorkWeekday(#importDate))
END
RETURN #importDate;
END
GO
Then how about:
declare #dt datetime='1 dec 2012'
select case when 8-##DATEFIRST=DATEPART(dw,#dt)
then DATEADD(d,-2,#dt)
when (9-##DATEFIRST)%7=DATEPART(dw,#dt)%7
then DATEADD(d,-3,#dt)
else DATEADD(d,-1,#dt)
end
The simplest solution to find the previous business day is to use a calendar table with a column called IsBusinessDay or something similar. The your query is something like this:
select max(BaseDate)
from dbo.Calendar c
where c.IsBusinessDay = 0x1 and c.BaseDate < #InputDate
The problem with using functions is that when (not if) you have to create exceptions for any reason (national holidays etc.) the code quickly becomes unmaintainable; with the table, you just UPDATE a single value. A table also makes it much easier to answer questions like "how many business days are there between dates X and Y", which are quite common in reporting tasks.
You can easily make this a function call, adding a second param to replace GetDate() with whatever date you wanted.
It will work for any day of the week, at any date range, if you change GetDate().
It will not change the date if the day of week is the input date (GetDate())
Declare #DayOfWeek As Integer = 2 -- Monday
Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - #DayOfWeek)) * -1) % 7, Convert(Date,GetDate()))
More elegant:
select DATEADD(DAY,
CASE when datepart (dw,Getdate()) < 3 then datepart (dw,Getdate()) * -1 + -1 ELSE -1 END,
cast(GETDATE() as date))
select
dateadd(dd,
case DATEPART(dw, getdate())
when 1
then -2
when 2
then -3
else -1
end, GETDATE())
thanks for the tips above, I had a slight variant on the query in that my user needed all values for the previous business date. For example, today is a Monday so he needs everything between last Friday at midnight through to Saturday at Midnight. I did this using a combo of the above, and "between", just if anyone is interested. I'm not a massive techie.
-- Declare a variable for the start and end dates.
declare #StartDate as datetime
declare #EndDate as datetime
SELECT #StartDate = DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
select #EndDate = #StartDate + 1
select #StartDate , #EndDate
-- Later on in the query use "between"
and mydate between #StartDate and #EndDate

Find the Friday that a particular date is "closest" to in T-Sql

I'm looking for an elegant simple way to determine the date of the Friday that is closest to a particular date. Any ideas?
The trick is to determine how many days away the closest Friday is from the offered date. To help, look at an entire week and the number of days away from the closest Friday:
Sunday -2
Monday -3
Tuesday 3
Wednesday 2
Thursday 1
Friday 0
Saturday -1
Now you need a formula to return these results. Because Sunday and Monday follow a different pattern from the other days of the week, two formulas are needed.
First, here is the one for Sunday and Monday. It adds 1 to the day of the week value then takes the negative to apply to the date add. For example, Monday has a default of 2 as the day of the week value. (2 + 1) * -1 = -3. -3 + Monday = Friday.
Tuesday - Saturday use similar arithmetic: The dates return the day of week values 3, 4, 5, 6, & 7. We need date add values of 3,2,1,0,-1 respectively. The formula to get this is DW * -1 + 6.
DECLARE #Date AS datetime
SET #Date = '3/1/2010'
SELECT
CASE
WHEN DATEPART(dw, #Date) <= 2
THEN DATEADD(d, -1 * (DATEPART(dw, #Date) + 1), #Date)
ELSE DATEADD(d, DATEPART(dw, #Date) * -1 + 6, #Date)
END AS NearestFriday
This returns a closest Friday in the future:
SELECT DATEADD(day, 6 - (DATEDIFF(day, '01/01/2010', #mydate) - 1) % 7, #mydate)
You have to slide the beginning of the week (using DATEFIRST) so that you get Tuesday becomes the middle of the week and then you just add the number of days to go to the closest Friday,.
SET NOCOUNT ON
SET DATEFIRST 3
Declare #DateValue DateTime
SET #DateValue = '1/1/2010'
While #DateValue < '2/1/2011'
BEGIN
PRINT DateAdd (Day, 3 - DatePart (dw, #DateValue), #DateValue)
SET #DateValue = #DateValue + 1
END
if you need to find the closest (past or future) Friday, try this:
DECLARE #StartDate datetime
,#EndDate datetime
,#BeforeDate datetime
SET #StartDate='2010-3-1'---<<<given date, Monday, closest should be '2010-2-26'
SET #EndDate=#StartDate+8
SET #BeforeDate=#StartDate-8
;with AllDates AS
(
SELECT #StartDate AS DateOf, 1 as TypeOf,DATENAME(weekday,#StartDate) AS WeekDayOf, ABS(DATEDIFF(day,#StartDate,#StartDate)) AS DifferenceOf
UNION ALL
SELECT DateOf+1 AS DateOf,2 AS TypeOf,DATENAME(weekday,DateOf+1 ) AS WeekDayOf, ABS(DATEDIFF(day,#StartDate,DateOf+1)) AS DifferenceOf
FROM AllDates
WHERE DateOf<#EndDate-1 AND TypeOf IN (1,2)
UNION ALL
SELECT DateOf-1 AS DateOf,3 AS TypeOf,DATENAME(weekday,DateOf-1 ) AS WeekDayOf, ABS(DATEDIFF(day,#StartDate,DateOf-1)) AS DifferenceOf
FROM AllDates
WHERE DateOf>#BeforeDate-1 AND TypeOf IN (1,3)
)
SELECT TOP 1 DateOf
FROM AllDates
WHERE WeekDayOf='Friday'
ORDER BY DifferenceOf
OUTPUT:
DateOf
-----------------------
2010-02-26 00:00:00.000
(1 row(s) affected)
SQL Server solution as a user-defined function. Will round not just to the nearest Friday, but to the nearest of any weekday (1-7) you specify:
CREATE FUNCTION RoundToNearestWeekday (
--Give this function a date, and the number of the weekday you want to round to the nearest of
#DateInput date, --Date you want to round
#ToWeekdayNumber tinyint --1 = round to nearest Sunday, 2 = round to nearest Monday, etc.
)
RETURNS date
AS
BEGIN
DECLARE #Offset tinyint, #LowNumber smallint, #HighNumber smallint, #NewDate date
SET #Offset = (#ToWeekdayNumber + 3)%7
SET #LowNumber = #Offset-3
SET #HighNumber = #Offset+4
SET #NewDate = dateadd(day,CASE WHEN datepart(weekday,#DateInput) <= #Offset THEN #LowNumber ELSE #HighNumber END - datepart(weekday,#DateInput),#DateInput)
RETURN #NewDate
END

Get day of week in SQL Server 2005/2008

If I have a date 01/01/2009, I want to find out what day it was e.g. Monday, Tuesday, etc...
Is there a built-in function for this in SQL Server 2005/2008? Or do I need to use an auxiliary table?
Use DATENAME or DATEPART:
SELECT DATENAME(dw,GETDATE()) -- Friday
SELECT DATEPART(dw,GETDATE()) -- 6
Even though SQLMenace's answer has been accepted, there is one important SET option you should be aware of
SET DATEFIRST
DATENAME will return correct date name but not the same DATEPART value if the first day of week has been changed as illustrated below.
declare #DefaultDateFirst int
set #DefaultDateFirst = ##datefirst
--; 7 First day of week is "Sunday" by default
select [#DefaultDateFirst] = #DefaultDateFirst
set datefirst #DefaultDateFirst
select datename(dw,getdate()) -- Saturday
select datepart(dw,getdate()) -- 7
--; Set the first day of week to * TUESDAY *
--; (some people start their week on Tuesdays...)
set datefirst 2
select datename(dw,getdate()) -- Saturday
--; Returns 5 because Saturday is the 5th day since Tuesday.
--; Tue 1, Wed 2, Th 3, Fri 4, Sat 5
select datepart(dw,getdate()) -- 5 <-- It's not 7!
set datefirst #DefaultDateFirst
SELECT CASE DATEPART(WEEKDAY,GETDATE())
WHEN 1 THEN 'SUNDAY'
WHEN 2 THEN 'MONDAY'
WHEN 3 THEN 'TUESDAY'
WHEN 4 THEN 'WEDNESDAY'
WHEN 5 THEN 'THURSDAY'
WHEN 6 THEN 'FRIDAY'
WHEN 7 THEN 'SATURDAY'
END
EUROPE:
declare #d datetime;
set #d=getdate();
set #dow=((datepart(dw,#d) + ##DATEFIRST-2) % 7+1);
To get a deterministic value for the day of week for a given date you could use a combination of DATEPART() and ##datefirst. Otherwise your dependent on the settings on the server.
Check out the following site for a better solution:
MS SQL: Day of Week
The day of week will then be in the range 0 to 6, where 0 is Sunday, 1 is Monday, etc. Then you can use a simple case statement to return the correct weekday name.
With SQL Server 2012 and onward you can use the FORMAT function
SELECT FORMAT(GETDATE(), 'dddd')
You can use DATEPART(dw, GETDATE()) but be aware that the result will rely on SQL server setting ##DATEFIRST value which is the first day of week setting (In Europe default value 7 which is Sunday).
If you want to change the first day of week to another value, you could use SET DATEFIRST but this may affect everywhere in your query session which you do not want.
Alternative way is to explicitly specify the first day of week value as parameter and avoid depending on ##DATEFIRST setting. You can use the following formula to achieve that when need it:
(DATEPART(dw, GETDATE()) + ##DATEFIRST + 6 - #WeekStartDay) % 7 + 1
where #WeekStartDay is the first day of the week you want for your system (from 1 to 7 which means from Monday to Sunday).
I have wrapped it into below function so we can reuse it easily:
CREATE FUNCTION [dbo].[GetDayInWeek](#InputDateTime DATETIME, #WeekStartDay INT)
RETURNS INT
AS
BEGIN
--Note: #WeekStartDay is number from [1 - 7] which is from Monday to Sunday
RETURN (DATEPART(dw, #InputDateTime) + ##DATEFIRST + 6 - #WeekStartDay) % 7 + 1
END
Example usage:
GetDayInWeek('2019-02-04 00:00:00', 1)
It is equivalent to following (but independent to SQL server DATEFIRST setting):
SET DATEFIRST 1
DATEPART(dw, '2019-02-04 00:00:00')
this is a working copy of my code check it, how to retrive day name from date in sql
CREATE Procedure [dbo].[proc_GetProjectDeploymentTimeSheetData]
#FromDate date,
#ToDate date
As
Begin
select p.ProjectName + ' ( ' + st.Time +' '+'-'+' '+et.Time +' )' as ProjectDeatils,
datename(dw,pts.StartDate) as 'Day'
from
ProjectTimeSheet pts
join Projects p on pts.ProjectID=p.ID
join Timing st on pts.StartTimingId=st.Id
join Timing et on pts.EndTimingId=et.Id
where pts.StartDate >= #FromDate
and pts.StartDate <= #ToDate
END
If you don't want to depend on ##DATEFIRST or use DATEPART(weekday, DateColumn), just calculate the day of the week yourself.
For Monday based weeks (Europe) simplest is:
SELECT DATEDIFF(day, '17530101', DateColumn) % 7 + 1 AS MondayBasedDay
For Sunday based weeks (America) use:
SELECT DATEDIFF(day, '17530107', DateColumn) % 7 + 1 AS SundayBasedDay
This return the weekday number (1 to 7) ever since January 1st respectively 7th, 1753.
In addition all with above answers, dw stands for Week Day
SELECT DATENAME(WEEKDAY,GETDATE()) AS WeekDay
or
SELECT DATENAME(W,GETDATE()) AS WeekDay
You may find this version useful for returning a shortened weekday name in one line.
-- Test DATA
select ##datefirst
create table #test (datum datetime)
insert #test values ('2013-01-01')
insert #test values ('2013-01-02')
insert #test values ('2013-01-03')
insert #test values ('2013-01-04')
insert #test values ('2013-01-05')
insert #test values ('2013-01-06')
insert #test values ('2013-01-07')
insert #test values ('2013-01-08')
-- Test DATA
select Substring('Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun,Mon,Tue,Wed,Thu,Fri,Sat',
(DATEPART(WEEKDAY,datum)+##datefirst-1)*4+1,3),Datum
from #test