Problem when getting the day name in SQL Server from a number - sql

I am trying to get the dayname from SQL, with as input only a number representing a day of the week.
When I run this code
select
datename(dw, '20210115'),
datepart(dw, '20210115')
it returns Friday, 6
So I thought that the number 6 means Friday
Then I do the following
select datename(dw, 6)
but instead of returning Friday it returns Sunday
So, what is the proper way to get the dayname from SQL Server with only a weekday number as input?

The DateName() and DatePart() rely on specific settings (e.g. SET DATEFIRST)
So whilst a value of 6 might represent "Friday" for you right now, the same code might return a different value in a different session for you or for other users.
This is why I don't use those functions, but instead create a calendar table with metadata to inform me of the week day.
The code I use looks like this:
...
, CASE WHEN DateDiff(dd, '1900-01-01', the_date) % 7 = 0 THEN 1 ELSE 0 END As is_monday
, CASE WHEN DateDiff(dd, '1900-01-01', the_date) % 7 = 1 THEN 1 ELSE 0 END As is_tuesday
, CASE WHEN DateDiff(dd, '1900-01-01', the_date) % 7 = 2 THEN 1 ELSE 0 END As is_wednesday
, CASE WHEN DateDiff(dd, '1900-01-01', the_date) % 7 = 3 THEN 1 ELSE 0 END As is_thursday
, CASE WHEN DateDiff(dd, '1900-01-01', the_date) % 7 = 4 THEN 1 ELSE 0 END As is_friday
, CASE WHEN DateDiff(dd, '1900-01-01', the_date) % 7 = 5 THEN 1 ELSE 0 END As is_saturday
, CASE WHEN DateDiff(dd, '1900-01-01', the_date) % 7 = 6 THEN 1 ELSE 0 END As is_sunday
...
This will work on all SQL Server databases, regardless of settings.
If you want this to just return the date name then it could be written as:
CASE DateDiff(dd, '1900-01-01', the_date) % 7
WHEN 0 THEN 'Monday'
WHEN 1 THEN 'Tuesday'
WHEN 2 THEN 'Wednesday'
WHEN 3 THEN 'Thursday'
WHEN 4 THEN 'Friday'
WHEN 5 THEN 'Saturday'
WHEN 6 THEN 'Sunday'
END AS day_of_week
How This Approach Works
We calculate the number of days between the input (in these examples the_date) and a known, fixed point in time.
The date 1900-01-01 is used because it is the "default" (not the right word, but I can't think of a better one right now!) i.e. what a value of 0 would be cast to.
1900-01-01 also happens to be a Monday!
Every 7th day after that is another Monday, which is what the modulus 7 (% 7) bit is responsible for working out!

Related

Can anyone explain this sql query clearly

Query will exclude weekends. In the query:
What is the * 2 doing in (DATEDIFF(wk, Startdate,Enddate) * 2)
Here Saturday how it will be minus (Saturday not mentioned)
(CASE WHEN DATENAME(dw, Startdate) = 'Sunday' THEN 1 ELSE 0 END)
Here how Sunday will minus (Sunday not mentioned)
(CASE WHEN DATENAME(dw, Enddate) = 'Saturday' THEN 1 ELSE 0 END)
In date diff(wk,startdate,enddate)*2) here how weekends finding and excluding exactly.
I am thinking like( 20 days-(20/7=2.6*2=5.8(Round to 6)-0-0) briefly(20-6-0-0= 14 days) is correct. but how it exactly identifying sat and sun.
I am correct or not. My question is why multiplying with 2 why can't with 3 or 4?
Query is working correctly. I am missing things in the query to understand.
Please see the query and explain clearly.
SELECT
Startdate, Enddate,
(DATEDIFF(dd, Startdate, Enddate)) -
(DATEDIFF(wk, Startdate, Enddate) * 2) -
(CASE WHEN DATENAME(dw, Startdate) = 'Sunday' THEN 1 ELSE 0 END) -
(CASE WHEN DATENAME(dw, Enddate) = 'Saturday' THEN 1 ELSE 0 END) AS workingdays
FROM
EMP_Table;
Line by line:
First get the raw number of days between the dates:
(DATEDIFF(dd, Startdate,Enddate))
Subtract the number of weekend days, which will be the number of weeks times 2
-(DATEDIFF(wk, Startdate,Enddate )*2)
Adjust for the case where the start date is a Sunday
-(CASE WHEN DATENAME(dw, Startdate) = 'Sunday' THEN 1 ELSE 0 END)
Adjust for the case where the end date is a Saturday
-(CASE WHEN DATENAME(dw, Enddate) = 'Saturday' THEN 1 ELSE 0 END)
As pr DATEDIFF() will return the difference between two date by given interval,
and
DATENAME() will return specific part of the date which here dw will return weekday it may any day of week like Sunday, Monday etc
Now Execution of Query:
For example:
Startdate='2019/10/6' and Enddate='2019/10/12'
DATEDIFF(dd, Startdate, Enddate) will give 6
DATEDIFF(wk, Startdate, Enddate) will give 0 and there are 2 days of weekend so 0*2=0
CASE WHEN DATENAME(dw, Startdate) = 'Sunday' THEN 1 ELSE 0 END will give 1 because it's a Sunday and same as for Enddate it's a 1 due to Saturday
So final equation is workingdays=(6-0-1-1) so it give result as workingdays=4

query criteria based on current day (sat/sun should return friday's value)

I'm trying to figure out how to return daily results throughout the week while keeping Friday's results visible over the weekend. My current code isn't doing the trick - do I have to mess with arrays?
SELECT ROUND(COUNT(ClosedDate) / 10, 0) * 10 [Previous Day Sales]
FROM PartsSales
WHERE (MONTH(ClosedDate) = MONTH(GETDATE())) AND (YEAR(ClosedDate) = YEAR(GETDATE())) AND (DAY(ClosedDate) = **case** DAY(GETDATE())
when 1 then 1
when 2 then 2
when 3 then 3
when 4 then 4
when 5 then 5
when 6 then 5
when 7 then 5 end
You can use datepart to find the current day of the week (1 = Sunday, 2 = Monday, etc), and then you can use dateadd to go back to Friday's date. If you convert getdate() to a date, then you'll always have the "midnight" at the begining of that day.
dateadd(
day,
case datepart(dw, getdate())
when 1 then -- Sunday
-2
when 7 then -- Saturday
-1
else -- Any other day
0
end,
convert(date, getdate())
)
Is your ClosedDate a datetime datatype? You can make much better use of your indexes by checking for a date range, rather than pulling the dateparts out (using year/month/day). Below is an example with a lot of resused code in the where clause. Of course, if it is just a date datatype, you don't even need a range, since you are calculating the date.
Below is an example. It would be better if you used variables (if you're building this into a stored proc), or perhaps a derived/CTE table. I've kept things verbose for clarity.
SELECT
ROUND(COUNT(ClosedDate) / 10, 0) * 10 [Previous Day Sales]
FROM
PartsSales
WHERE
ClosedDate between
-- Today/Friday's date:
dateadd(
day,
case datepart(dw, getdate())
when 1 then -- Sunday
-2
when 7 then -- Saturday
-1
else -- Any other day
0
end,
convert(date, getdate())
)
and
-- Add 1 day to the "Today/Friday" date.
-- This is the same logic as above, except wrapped in an extra dateadd to add 1 day to it.
dateadd(
day,
1,
dateadd(
day,
case datepart(dw, getdate())
when 1 then -- Sunday
-2
when 7 then -- Saturday
-1
else -- Any other day
0
end,
convert(date, getdate())
)
)

On Monday pull data from Friday to Sunday, on other weekdays from prior day only

I have this query which is currently pulling all incidents from a SQL Server database which were closed on prior weekday. It's pretty neat as it's using modulo to be independent over ##DATEFIRST local settings. However I need to amend it in a way that on Mondays it gives me all incidents closed between Friday and Sunday.
Current code:
SELECT
inc.Incident_Id, inc.Close_Time
FROM
inc
WHERE
CONVERT (CHAR(10), inc.Close_Time, 126) = CONVERT (CHAR(10), (DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7
WHEN 1 THEN -2
WHEN 2 THEN -3
ELSE -1
END, DATEDIFF(DAY, 0, GETDATE()))),126)
I tried using another CASE DATEPART(WEEKDAY, GETDATE()) before first CONVERT but it didn't work out as it looked like >= and <= (or BETWEEN & AND) are not allowed both in one condition after THEN.
To sum up it should be like this:
On Mondays - incidents closed between Friday and Sunday
On other weekdays - incidents closed on prior day
Try this:
DECLARE #from date =
DATEADD(day,
CASE datediff(d, 0, getdate()) %7
WHEN 0 THEN -3
WHEN 6 THEN -2
ELSE -1
END, getdate())
SELECT inc.Incident_Id, inc.Close_Time
FROM inc
WHERE
inc.Close_Time >= #from
AND inc.Close_Time < #to
Monday and Sunday will return friday and after
Tuesday to saturday will return the day before.

SSRS - How to group Date into Today/Yesterday/Week/Month in a Matrix?

I have data sorted by dates:
e.g.
Region - Date - Count
East - 2012/01/01 - 5
West - 2012/01/01 - 2
East - 2012/01/06 - 3
South - 2012/01/07 - 3
etc
I'm trying to create a sum of the Counts, grouped by date groups relative to today. So for example
Assuming today was 2012/01/07:
Yesterday is defined to be from Today - 1 to today (non-inclusive of
today)
Week is defined to be from Today - 7 to today (non-inclusive of
today)
Month is defined to be from Today - 28 to today (non-inclusive
of today)
The output in the matrix for the sample data would be:
As a bonus, ideally I'd have a 5th column that's for "On Demand" Start and End date range for the user to input.
I think the key is to add an EXPR in the Column Group's Group On property but I don't know what the Expression should be.
Any help would be great!
Personally I think I would prefer to attack it in the SQL query. So for example
SELECT
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) = 0 THEN SomeColumn ELSE 0 END cToday
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) = 1 THEN SomeColumn ELSE 0 END cYesterday
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) > 0 AND
DATEDIFF(day, GETDATE(), DateColumn) < 8 THEN SomeColumn ELSE 0 END cWeek
CASE WHEN DATEDIFF(day, GETDATE(), DateColumn) > 0 THEN SomeColumn ELSE 0 END cMonth
FROM
SomeTable
WHERE
DateColumn > DATEADD(day, -28, GETDATE())
Otherwise you could use a similar approach inside SSRS

How do I search and group by a date column into sets of duration ranges?

I have a table like this;
jobID - jobTitle - jobCreatedDate
I want to make it possible for visitors to search in Jobs table and list it by grouping like this and I want to do it with just one SQL query:
Date Added
- AnyTime (20)
- 1 day ago (5)
- 2-7 days ago (2)
- 8-14 days ago (0)
- 15-30 days ago (7)
I tried Group By "jobCreatedDate" with no success and I couldn't understand the logic of the necessary query.
Here is an example what I'm trying to do:
Thanks for help.
You need to find the date difference between today and the field JobCreated. Then based on the difference in the value days, you need to classify the output accordingly into various categories to meet your requirements.
I hope that is what you are looking for.
SELECT SUM(1) AS [AnyTime]
, SUM(CASE WHEN DayCount = 1 THEN 1 ELSE 0 END) AS [1 day ago]
, SUM(CASE WHEN DayCount BETWEEN 2 AND 7 THEN 1 ELSE 0 END) AS [2-7 days ago]
, SUM(CASE WHEN DayCount BETWEEN 8 AND 14 THEN 1 ELSE 0 END) AS [8-14 days ago]
, SUM(CASE WHEN DayCount BETWEEN 15 AND 30 THEN 1 ELSE 0 END) AS [15-30 days ago]
FROM
(
SELECT JobID
, DATEDIFF(d, JobCreatedDate, GETDATE()) AS DayCount
FROM dbo.Jobs
) Jobs
Screenshot shows sample data and the query output.
Use the DATEADD tsql method.
Select ...
From [Table]
Where JobCreatedDate between DATEADD(dd, #NumDays, GetDate()) and GetDate()
In this query #NumDays is a parameter representing the number of days to subtract from the current date. Make sure you pass a negative number to the query. If you are trying to create non inclusive ranges, you'll need to use two DATEADD calls passing two parameters to the query.
EDIT
I misunderstood what you were trying to do. This may not be the most elegant solution, but you could accomplish your goal using a union query.
Select sum(OneDay) as OneDay, sum(SevenDays) as SevenDays
From
(select 1 as OneDay, 0 as SevenDays
From [table]
Where JobCreatedDate between DATEADD(dd, -1, GetDate()) and GetDate())
UNION
(select 0 as OneDay, 1 as SevenDays
From[table]
Where JobCreatedDate between DATEADD(dd, -7, GetDate()) and DATEADD(dd, -2, GetDate()))