SQL DATEPART(dw,date) need monday = 1 and sunday = 7 - sql

I have a Query where I get the WeekDay of a date but by default:
Sunday = 1
Moday = 2
etc.
The function is:
DATEPART(dw,ads.date) as weekday
I need the result so:
Sunday = 7
Monday = 1
etc.
Is there any shortcut to do this? Or I will have to do a CASE statement?

This will do it.
SET DATEFIRST 1;
-- YOUR QUERY
Examples
-- Sunday is first day of week
set datefirst 7;
select DATEPART(dw,getdate()) as weekday
-- Monday is first day of week
set datefirst 1;
select DATEPART(dw,getdate()) as weekday

You can use a formula like:
(weekday + 5) % 7 + 1
If you decide to use this, it would be worth running through some examples to convince yourself that it actually does what you want.
addition:
for not to be affected by the DATEFIRST variable (it could be set to any value between 1 and 7) the real formula is :
(weekday + ##DATEFIRST + 5) % 7 + 1

You can tell SQL Server to use Monday as the start of the week using DATEFIRST like this:
SET DATEFIRST 1

I would suggest that you just write the case statement yourself using datename():
select (case datename(dw, aws.date)
when 'Monday' then 1
when 'Tuesday' then 2
when 'Wednesday' then 3
when 'Thursday' then 4
when 'Friday' then 5
when 'Saturday' then 6
when 'Sunday' then 7
end)
At least, this won't change if someone changes the parameter on the day of the week when weeks begin. On the other hand, it is susceptible to the language chosen for SQL Server.

You can use this formula regardless of DATEFIRST setting :
((DatePart(WEEKDAY, getdate()) + ##DATEFIRST + 6 - [first day that you need] ) % 7) + 1;
for monday = 1
((DatePart(WEEKDAY, getdate()) + ##DATEFIRST + 6 - 1 ) % 7) + 1;
and for sunday = 1
((DatePart(WEEKDAY, getdate()) + ##DATEFIRST + 6 - 7 ) % 7) + 1;
and for friday = 1
((DatePart(WEEKDAY, getdate()) + ##DATEFIRST + 6 - 5 ) % 7) + 1;

Another solution is the following:
ISNULL(NULLIF(DATEPART(dw,DateField)-1,0),7)

This is caused by the account the SQL Server service is run under. For example;
If the SQL Server Service is run under DOMAIN\MyUserAccount then this will need to be a login and set with the relevant Language.
If this account isn't set then SQL Server will default to the sa account and the Language that runs under.
I found that our sa account was set to English which had Monday as DW = 2. The DOMAIN\MyUserAccount Account was setup and changed to British English and DW for Monday was being returned as 1.
Hope this helps

Simply subtract one day from your ads.date field and use in DATEPART function:
DATEPART(dw,DATEADD(day,-1,ads.date)) as weekday

I think this could work:
select
case when datepart(dw,[Date]) = 1 then 7 else DATEPART(DW,[Date])-1 end as WeekDay

Try this:
CREATE FUNCTION dbo.FnDAYSADDNOWK(
#addDate AS DATE,
#numDays AS INT
) RETURNS DATETIME AS
BEGIN
WHILE #numDays > 0 BEGIN
SET #addDate = DATEADD(day, 1, #addDate)
IF DATENAME(DW, #addDate) <> 'sunday' BEGIN
SET #numDays = #numDays - 1
END
END
RETURN CAST(#addDate AS DATETIME)
END

Looks like the DATEFIRST settings is the only way, but it's not possible to make a SET statement in a scalar/table valued function. Therefore, it becomes very error-prone to the colleagues following your code. (become a trap to the others)
In fact, SQL server datepart function should be improved to accept this as parameter instead.
At the meantime, it looks like using the English Name of the week is the safest choice.

-- Monday is first day of week set datefirst 1; select DATEPART(dw,getdate()) as weekday
SQLChao answer still works prefectly well

You would need to set DATEFIRST. Take a look at this article. I believe this should help.
https://learn.microsoft.com/en-us/sql/t-sql/statements/set-datefirst-transact-sql

I think
DATEPART(dw,ads.date - 1) as weekday
would work.

Related

How to make a datepart() function in a view accept Monday as the first day of the week

For a webapplication I created the following view:
alter view [dbo].[vwBookingData]
as
select concat(rtrim(ltrim(str(datepart(year, bookingdata.booking_datetime)))), '-', rtrim(ltrim(str(datepart(week, bookingdata.booking_datetime))))) as WeekNumber,
bookingdata.booking_customerCode as ClientCode, customer.Name as ClientName, concat(bookingdata.booking_provider, concat('-', bookingdata.booking_system)) as ProviderCombo,
bookingdata.segments_carrierCode as CarrierCode, bookingdata.booking_datetime as BookingDate, bookingdata.booking_bookingId, flgConfirmed, flgFailed
from dbo.flights_bookingdata bookingdata
inner join dbo.Customer on Customer.Number = bookingdata.booking_customerCode
My problem is 1 specific part of the used query:
datepart(week, bookingdata.booking_datetime)
I have noticed the datepart() appears to take a week starts on Sunday rather than on Monday, this breaks the overview the view is supposed to generate.
Is there a way I can fix this within the query itself?
Perhaps you can try (I was right first with 1 not 2)
SET DATEFIRST 1;
At the top of your query
SET DATEFIRST 7; -- The Default
Select *
,WeedDay=DateName(DW,RetVal)
,WeekNo=DatePart(WK,RetVal)
From [dbo].[udf-Range-Date]('2016-10-01','2016-10-14','DD',1)
While
SET DATEFIRST 1;
Select *
,WeedDay=DateName(DW,RetVal)
,WeekNo=DatePart(WK,RetVal)
From [dbo].[udf-Range-Date]('2016-10-01','2016-10-14','DD',1)
Seeing that you can’t use the SET DATEFIRST option I would simply subtract one day from the datetime when you call the DATEPART function as follow:
DATEPART(WEEK, DATEADD(DAY, -1, bookingdata.booking_datetime))
With this function you can return the day of the week, starting from monday, in any server language or DATEFIRST setting:
-- =============================================
-- Author: Javier Cañon
-- Create date: 2019-04-23
-- Description: Return day of week without know of server SET DATEFIRST setting
-- =============================================
CREATE FUNCTION [dbo].[fnGetWeekDayFromMonday]
(
-- Add the parameters for the function here
#SomeDate DATE
)
RETURNS int
AS
BEGIN
DECLARE #SqlWeekDay INT, #ResultVar int;
SET #SqlWeekDay= DATEPART(dw, #SomeDate);
SET #ResultVar = ((#SqlWeekDay + ##DATEFIRST - 1 - 1) % 7) + 1;
-- Return the result of the function
RETURN #ResultVar;
END
GO

I need to create a function that will return number of day in a week on requested date

Something like this (which is not working)
CREATE FUNCTION dbo.udf_DayOfWeek
(#b_date DATETIME)
RETURNS VARCHAR(10)
AS
BEGIN
DECLARE #weekday VARCHAR(10)
IF (SELECT DATENAME(dw, #b_date)
RETURN (#weekday)
END;
GO
after using this
SELECT dbo.udf_DayOfWeek ('May 22, 2016');
GO
to return value of 1-7(number of a day in week)
I am using SQL Server 2014
You are going to want to use DATEPART() versus DATENAME() to get the numeric value, but this can be done inline and really doesn't need it's own function.
SELECT DATEPART(weekday,'May 22, 2016')
And to fix your function syntax...
CREATE FUNCTION dbo.udf_DayOfWeek (#b_date DATETIME)
RETURNS INT
AS
BEGIN
DECLARE #weekday INT
SELECT #weekday = DATEPART(WEEKDAY, #b_date)
RETURN (#weekday)
END
GO
DatePart for weekday uses the DateFirst setting, making it difficult to use consistently. The problem is, some places in the world consider Sunday to be the first day of the week, and other places consider Monday to be the first day of the week. Because of this ambiguity, SQL Server will use the datefirst setting of the login currently connected to the database. To see a list of datefirst settings, run this:
Select * From sys.syslanguages
You can manually set the DateFirst value that persists for the duration of the connection like this:
Set DateFirst 1
SELECT DATEPART(weekday,'May 22, 2016')
Set DateFirst 7
SELECT DATEPART(weekday,'May 22, 2016')
Note that the output of the previous code changes depending on the DateFirst setting.
If you want 1 to always represent Sunday, regardless of the user's language setting, you can use this:
Select DateDiff(Day, 6,#DateVariable) % 7 + 1
Using this information, you can create your user defined function like this:
CREATE FUNCTION dbo.udf_DayOfWeek
(#b_date DATETIME)
RETURNS int
AS
BEGIN
return (
Select DateDiff(Day, 6,#b_date) % 7 + 1
)
END;

How to find closest FRI?

In SQL Server 2008, given a date, how would I get a date corresponding to FRI of that week?
so for example:
6/6/2012 -> 6/8/2012
6/5/2012 -> 6/8/2012
Assuming you want 6/9/2012 to also return 6/8/2012 (same week), this would work.
It get's the day of week of the current date and adds the difference between that and Friday which is hardcoded to a value of 6.
SET DATEFIRST 7;
declare #date date = '6/5/2012'
select dateadd(dd,6-datepart(dw,#date),#date) as Friday
If you want 6/9/2012 to return the next Friday, you just have to make a small modification:
SET DATEFIRST 7;
declare #date date = '6/9/2012'
set #date = dateadd(dd,1,#date) -- this adds a day to the date you inputted but doesn't matter since the function will always return to you a Friday
-- Sunday resets the week with datepart so adding a day to Saturday resets the week resulting in the next week being returned.
select dateadd(dd,6-datepart(dw,#date),#date) as Friday
Here's a function I created that seems to work. It does not change DATEFIRST and will give you the next date for the DOW. The function will return the date you passed in if it is on the DOW you are looking for.
CREATE FUNCTION [dbo].[func_NextDate]
(
#dt DATE,
#dow INT -- Use the day-of-week as defined by SQL Server (1=Sun, 7=Sat)
)
RETURNS DATE
AS
BEGIN
DECLARE #dtDiff INT = 7-((DATEPART(dw, #dt)+(7-#dow))%7)
IF #dtDiff = 7
SET #dtDiff = 0 -- Return the date if it is on the dow requested
RETURN DATEADD(dd, #dtDiff, #dt)
END

SQL Server SET DATEFIRST scope

I'm using SS 2005 if that
I've seen sample code like
DECLARE #restore = SELECT ##DATEFIRST
SET DATEFIRST 1
SELECT datepart(dw,ADateTimeColumn) as MondayBasedDate,.... FROM famousShipwrecks --
SET DATEFIRST #restore
Suppose while the query is running another query sets DATEFIRST?
If another query relies on datefirst being 7 (for example) and doesn't set it, and runs while my query is running, that's his problem for not setting it? or is there a better way to write queries that depend on a given day being day number 1.
##DATEFIRST is local to your session. You can verify it by opening to tabs in Sql Server Management Studio (SSMS). Execute this code in the first tab:
SET DATEFIRST 5
And verify that it doesn't affect the other tab with:
select ##datefirst
See this MSDN article.
Just an additional point, if you want to avoid setting DATEFIRST you can just incorporate the value of DATEFIRST in your query to find your required day as :
SELECT (datepart(dw,ADateTimeColumn) + ##DATEFIRST) % 7) as 'MondayBasedDate'
, ...
FROM famousShipwrecks --
Then you dont need to worry about restoring it at all!
To setup a parameterized first day of the week, the following should work
DECLARE #FirstDayOfWeek INT = 1;
DECLARE #DateTime DATETIME = '2015-07-14 8:00:00';
SELECT (DATEPART(weekday, #DateTime) + ##DateFirst - #FirstDayOfWeek - 1) % 7 + 1;
You can forget about DATEPART(weekday, DateColumn) and ##DATEFIRST and instead 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 works fine ever since January 1st respectively 7th, 1753.

SQL Server: Get data for only the past year

I am writing a query in which I have to get the data for only the last year. What is the best way to do this?
SELECT ... FROM ... WHERE date > '8/27/2007 12:00:00 AM'
The following adds -1 years to the current date:
SELECT ... From ... WHERE date > DATEADD(year,-1,GETDATE())
I found this page while looking for a solution that would help me select results from a prior calendar year. Most of the results shown above seems return items from the past 365 days, which didn't work for me.
At the same time, it did give me enough direction to solve my needs in the following code - which I'm posting here for any others who have the same need as mine and who may come across this page in searching for a solution.
SELECT .... FROM .... WHERE year(*your date column*) = year(DATEADD(year,-1,getdate()))
Thanks to those above whose solutions helped me arrive at what I needed.
Well, I think something is missing here. User wants to get data from the last year and not from the last 365 days. There is a huge diference. In my opinion, data from the last year is every data from 2007 (if I am in 2008 now). So the right answer would be:
SELECT ... FROM ... WHERE YEAR(DATE) = YEAR(GETDATE()) - 1
Then if you want to restrict this query, you can add some other filter, but always searching in the last year.
SELECT ... FROM ... WHERE YEAR(DATE) = YEAR(GETDATE()) - 1 AND DATE > '05/05/2007'
The most readable, IMO:
SELECT * FROM TABLE WHERE Date >
DATEADD(yy, -1, CONVERT(datetime, CONVERT(varchar, GETDATE(), 101)))
Which:
Gets now's datetime GETDATE() = #8/27/2008 10:23am#
Converts to a string with format 101 CONVERT(varchar, #8/27/2008 10:23am#, 101) = '8/27/2007'
Converts to a datetime CONVERT(datetime, '8/27/2007') = #8/27/2008 12:00AM#
Subtracts 1 year DATEADD(yy, -1, #8/27/2008 12:00AM#) = #8/27/2007 12:00AM#
There's variants with DATEDIFF and DATEADD to get you midnight of today, but they tend to be rather obtuse (though slightly better on performance - not that you'd notice compared to the reads required to fetch the data).
Look up dateadd in BOL
dateadd(yy,-1,getdate())
GETDATE() returns current date and time.
If last year starts in midnight of current day last year (like in original example) you should use something like:
DECLARE #start datetime
SET #start = dbo.getdatewithouttime(DATEADD(year, -1, GETDATE())) -- cut time (hours, minutes, ect.) -- getdatewithouttime() function doesn't exist in MS SQL -- you have to write one
SELECT column1, column2, ..., columnN FROM table WHERE date >= #start
I, like #D.E. White, came here for similar but different reasons than the original question. The original question asks for the last 365 days. #samjudson's answer provides that. #D.E. White's answer returns results for the prior calendar year.
My query is a bit different in that it works for the prior year up to and including the current date:
SELECT .... FROM .... WHERE year(date) > year(DATEADD(year, -2, GETDATE()))
For example, on Feb 17, 2017 this query returns results from 1/1/2016 to 2/17/2017
For some reason none of the results above worked for me.
This selects the last 365 days.
SELECT ... From ... WHERE date BETWEEN CURDATE() - INTERVAL 1 YEAR AND CURDATE()
The other suggestions are good if you have "SQL only".
However I suggest, that - if possible - you calculate the date in your program and insert it as string in the SQL query.
At least for for big tables (i.e. several million rows, maybe combined with joins) that will give you a considerable speed improvement as the optimizer can work with that much better.
argument for DATEADD function :
DATEADD (*datepart* , *number* , *date* )
datepart can be: yy, qq, mm, dy, dd, wk, dw, hh, mi, ss, ms
number is an expression that can be resolved to an int that is added to a datepart of date
date is an expression that can be resolved to a time, date, smalldatetime, datetime, datetime2, or datetimeoffset value.
declare #iMonth int
declare #sYear varchar(4)
declare #sMonth varchar(2)
set #iMonth = 0
while #iMonth > -12
begin
set #sYear = year(DATEADD(month,#iMonth,GETDATE()))
set #sMonth = right('0'+cast(month(DATEADD(month,#iMonth,GETDATE())) as varchar(2)),2)
select #sYear + #sMonth
set #iMonth = #iMonth - 1
end
I had a similar problem but the previous coder only provided the date in mm-yyyy format. My solution is simple but might prove helpful to some (I also wanted to be sure beginning and ending spaces were eliminated):
SELECT ... FROM ....WHERE
CONVERT(datetime,REPLACE(LEFT(LTRIM([MoYr]),2),'-
','')+'/01/'+RIGHT(RTRIM([MoYr]),4)) >= DATEADD(year,-1,GETDATE())
Here's my version.
YEAR(NOW())- 1
Example:
YEAR(c.contractDate) = YEAR(NOW())- 1
For me this worked well
SELECT DATE_ADD(Now(),INTERVAL -2 YEAR);
If you are trying to calculate "rolling" days, you can simplify it by using:
Select ... FROM ... WHERE [DATE] > (GETDATE()-[# of Days])