Business starts from Monday and ends on Sunday as a complete week. So I need to group by week in SSRS. How can I do this?
I am attaching the screenshot of my requirement.
Any help will be greatly appreciated.
User SET DATEFIRST 1;
DATEFIRST will set the first day of the week according to value given. 1 is for Monday, 2 TUESDAY and so on.
It will always have a fixed value for days. Like 1 will always be Monday and 7 will always be Sunday.
SELECT ##DATEFIRST will give the Week start day. By default it will be 7 i.e. Sunday. So if you run SET DATEFIRST 1 then SELECT ##DATEFIRST will return 1.
You may have to put SET DATEFIRST 1 inside Stored Procedure along with your query.
Related
I have read this documentation
So I tried this experiment
declare #t table (test date)
insert into #t values ('20220404'), ('20220405'),('20220406'),('20220407'),('20220408'),('20220409'),('20220410')
select datename(weekday, test),
datepart(weekday, test)
from #t
it returns this
COLUMN1
COLUMN2
Monday
2
Tuesday
3
Wednesday
4
Thursday
5
Friday
6
Saturday
7
Sunday
1
I checked my value or ##DATEFIRST
select ##DATEFIRST
it returns 7
So why do I not get this result then as described in the docs?
COLUMN1
COLUMN2
Monday
1
Tuesday
2
Wednesday
3
Thursday
4
Friday
5
Saturday
6
Sunday
7
EDIT
this is what I see in the docs
I think you may be misunderstanding the docs. The docs for DATEFIRST say, as you've seen:
Sets the first day of the week
So, the value of DATEFIRST determines which day gets numbered 1, the first day of the week. With DATEFIRST set to 7, as the table goes on to show, Sunday will be considered the first day of the week - day number 1.
With that setting, DATEPART for weekday will return 1 for any Sunday, because Sunday is considered the first day of the week.
It is perhaps unfortunate that numbers are used as the argument to SET DATEFIRST, since naturally this confusion arises. It might have been nice if we could say SET DATEFIRST Sunday to make it obvious what we mean, but unfortunately that's not the syntax.
Sorry if the Title is confusing but it's hard to explain what I'm after in one phrase.
I'm currently producing a report based on the production for the week. I start off my CTE construction with the following to get the days Monday to Friday of the current week:
WITH
cte_Date AS
(
SELECT
CAST(DateTime AS date) AS Date
FROM
( VALUES
(GETDATE()
)
, (DATEADD(day,-1,GETDATE()))
, (DATEADD(day,-2,GETDATE()))
, (DATEADD(day,-3,GETDATE()))
, (DATEADD(day,-4,GETDATE()))
, (DATEADD(day,-5,GETDATE()))
, (DATEADD(day,-6,GETDATE())) ) AS LastSevenDays(DateTime)
WHERE
DATENAME(weekday, DateTime) = 'Monday'
UNION ALL
SELECT
DATEADD(day,1,Date)
FROM
cte_Date
WHERE
DATENAME(weekday,Date) <> 'Friday'
)
This is working fine. I have made the report available to users so they can run it anytime however sometimes nobody is available to run it last thing Friday. This means they don't get to see the full production for Friday and then the following week the CTE days change.
I'm trying to keep this a one-click affair so rather than introduce date parameters I proposed to the users that we adjust the query such that if they run the report before midday on "Monday" then it will show them last week's figures and they were happy with this (me and my big mouth). I put Monday in quotes because what we really mean of course is the first production day of the week.
My primary data table (which we'll call MyData) has a datetime field named DateTime (really!) that I can reference to determine the first day of production for the week.
One final caveat: Due to the layout of the report the users insisted that they always want to see the five days Monday to Friday, even if there is no production on a given day. (Consequently I do a LEFT JOIN from cte_Date to all other tables required.) So to be clear, right now as I'm typing this it's 11:45am local time on Tuesday and yesterday happened to be a public holiday here so running the report now should return Monday to Friday last week, but running it in 20 minutes time should return Monday to Friday this week.
Please help, my poor brain is getting twisted trying to figure it out.
There are a few different ways you can tackle this, but they all boil down to the same thing: you need a way of figuring out whether it's before or after 12pm on the first working day of the current week, then you need to get the Monday of the current "production week".
Let's just say, for simplicity's sake, you have some sort of table that contains public holidays (or non-production days). To find out whether it's the first day of the current production week, you basically just have to add the number of days in a row since the start of the week that have been public holidays.
Then you need to figure out whether it's before or after 12pm of that day.
If it's before you want last week's Monday-Friday. If it's after, you want this week's Monday-Friday.
Here's one way you might do this:
DECLARE #NonProductionDays TABLE (NPD DATE UNIQUE NOT NULL); -- Public holiday table.
INSERT #NonProductionDays (NPD) VALUES ('2017-09-25');
DECLARE #i INT = -- You don't need a variable for this, but just to keep things simple...
(
SELECT COUNT(*) -- Extract number of public holidays in a row this week before current date.
FROM #NonProductionDays AS N
WHERE DATEDIFF(WEEK, 0, N.NPD) = DATEDIFF(WEEK, 0, GETDATE())
AND N.NPD <= GETDATE()
AND (DATENAME(WEEKDAY, N.NPD) = 'Monday' OR EXISTS (SELECT 1 FROM #NonProductionDays AS N2 WHERE N2.NPD = DATEADD(DAY, -1, N.NPD)))
);
SELECT D = CAST(DATEADD(DAY, T.N, DATEADD(WEEK, DATEDIFF(HOUR, DATEADD(DAY, #i, '1900-01-01 12:00:00'), GETDATE()) / 24 / 7, '1900-01-01')) AS DATE)
FROM (VALUES (0), (1), (2), (3), (4)) AS T(N);
/*
Breaking this down:
X = DATEADD(DAY, #i, '1900-01-01 12:00:00')
-- Adds the number of NPD days this week to '1900-01-01 12:00:00'
-- So, for example, X would be '1900-01-02 12:00:00' this week
Y = DATEDIFF(HOUR, X, GETDATE()) / 24 / 7
-- The number of weeks between X and now, by taking the number of hours and dividing by 24 then by 7
-- The division is necessary to compare the hour.
-- So, for example, as of 11am on the September 26 2017, you'd get 6142.
-- As of 12pm on September 26 2017, you'd get 6143.
Z = DATEADD(WEEK, Y, '1900-01-01')
-- Just adds Y weeks to 1900-01-01, which was a Monday. This tells you the Monday of the current "production week".
-- So, for example, as of 11am on September 26 2017, you'd get '2017-09-18 00:00:00.000'.
-- As of 12pm on September 26 2017, you'd get '2017-09-25 00:00:00.000'.
Then we cast this as a date and add 0/1/2/3/4 days to it to get Monday, Tuesday, Wednesday, Thursday and Friday of the current "production week".
*/
I'm not sure I came up with the most efficient approach, but after a week of tossing it about in my brain this is what I came up with. I approached the problem from the opposite direction of that suggested by #ZLK.
My existing logic was already giving me the Monday of this week so in a subquery I looked for the first production record after Monday, stripped off the time with a DATEDIFF and made it midday with a DATEADD. I was then able to compare the current Date/Time with midday of the first production day to determine whether to reduce the date by one week.
I replaced this SELECT clause:
SELECT
CAST(DateTime AS date) AS Date
with this one:
SELECT -- Monday this week if it's after midday on the first production day otherwise Monday last week
DATEADD(week,IIF(GETDATE()>=DATEADD(hour,12,(
SELECT DATEDIFF(day,0,MIN(DateTime))
FROM MyData
WHERE CAST(MyData.DateTime AS date) >= CAST(LastSevenDays.DateTime AS date)
)),0,-1),CAST(LastSevenDays.DateTime AS date)) AS Date
To cater for the case where a new week has commenced but the operator runs the report before production starts I carefully arranged the boolean condition inside my IIF clause so that the empty result set from the subquery would mean the test returned FALSE and the operator would still see last week's figures.
(#ZLK, Thanks for your input - you did help my thinking a bit but I don't think your answer should be marked as correct. What I've come up with here is what I was originally requesting and didn't require the use of a static table.)
I am setting the DATEFIRST to start on Monday using this command.
SET DATEFIRST 1;
My question is: will this permanently set date first to Monday for the entire DB and users? Or will it only affect this one query?
If it only affects the query it is run with, what type of command would I need to permanently change the DATEFIRST to Monday for all users/entire DB?
The default first day of week is based on your system setting in Regional and Language setting. By default it is Sunday = 7 (U.S. English).
As Microsoft website shows, the days are as following:
Value First day of the week is
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
7 Sunday(default, U.S. English)
An example to know which day is the first day:
SELECT ##DATEFIRST AS 'First Day',
DATEPART(dw, SYSDATETIME()) AS 'Today'
My requirement is that I want to find business-week-ending (not the calender week) given a DATE column from the sales table in MSSQL.
Using different techniques I was able to find the [Calender] week-endings (and week-starting) dates corresponding to DATE in the table.
Since our business week ends on Wednesday [DOW 3 or 4 depending when the week started], I tried to deduct number of days from the week ending dates to pull it back to Wednesday. The idea did work pretty good with a flaw. Works fine as long as the Date in the table is greater than DOW 3 or 4. Any suggestion?
SELECT DateAdd(wk, DateDiff(wk, 0, Recons_Sales_Details.Recons_Date), 0) + 2
You need to look into SET DATEFIRST to do this:
SET DATEFIRST 4 --4 is Thursday week start
SQL Fiddle Demo
I would like to write a simple SELECT statement in SQL Server 2005 which does the following computation with date arithmetic:
Starting from the present date (this means getdate()), determine the previous Monday, and then subtract 70 days from that Monday, showing in output the resulting date.
How could I achieve this?
My difficulty is mainly to determine the previous Monday.
Of course, if getdate() is Monday, the previous Monday is getdate()
Thank you in advance for your kind help.
UltraCommit
EDIT: Please note that in Italy the first day of the week is Monday and not Sunday, so if the input is Sunday, July 29th, 2012, the output has to be 23rd July, and not 30th July.
This will retrieve monday for the current week
Select DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0)
and then you need to subtract 70 from the above day
SELECT Dateadd(DAY,-70,DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0))
Edit : Please go through the answer posted in SO
Monday is displayed as Current Week because DATEFIRST which indicates the 1st day of the week is set to monday .In order to set it to Sunday ,you need to change the setting to Sunday
Set DATEFIRST 7
Else as suggested in the above SO link ,you need to change your code
DECLARE #dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, #dt, CURRENT_TIMESTAMP), #dt);
To get last monday look at
http://blog.sqlauthority.com/2007/08/20/sql-server-find-monday-of-the-current-week/
This should get you started. It will find the past Monday for the current week.
SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0) MondayOfCurrentWeek
To substract 70 days, just add -70 to the end:
SELECT DATEADD(wk, DATEDIFF(wk,0,GETDATE()), 0)-70 as SomeMondayInHistory