SQL: First day of week Monday - sql

I would like to display Monday as the first day of the week and Sunday the last day of the week.
I am using for this report the Report server.
my query:
Select
Datum,
Sum(Prod) as Prod
FROM (
Select
intervaldate as Datum,
Sum(case when TabName = 'Produzierte Dosen' then DisplayUnits else 0 end) as Prod
from vwOeeIntervalCount
where
IntervalDateWeek >= dateadd(wk, datediff(wk, 0, getdate()) - 1, 0)
and IntervalDateWeek < dateadd(wk, datediff(wk, 0, getdate()), 0)
and IntervalDate >= dateadd(day,datediff(day,0,GETDATE())-6,0)
AND IntervalDate < dateadd(day,datediff(day,0,GETDATE()),0)
and CalculationName = 'Packaging'
group by intervaldate
)c
group by Datum
Here the result:
Date |Prod
2018-02-25 00:00:00.000 |1836528
2018-02-26 00:00:00.000 |8131127,99999999
EDIT:
Sorry here is my question.
I would like to display the Monday as the first day of the week. My query displays the Sunday as the first day of the week.
How can I do that?

By default MS SQL Server has configured sunday as first day of a week.
You can set the server config for the first day of a week to any day with the following command:
SET DATEFIRST { number | #number_var }
Value First day of the week is
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
7 (default, U.S. English) Sunday
Source: https://learn.microsoft.com/en-us/sql/t-sql/statements/set-datefirst-transact-sql

you can use this to the current week:
/*-- Week Start
--1->Sunday --2->Monday....*/
SELECT CAST(DATEADD(dd, -(DATEPART(dw, GETDATE()))+2, GETDATE()) AS DATE) [WeekStart],
CAST(DATEADD(dd, 8-(DATEPART(dw, GETDATE())), GETDATE()) AS DATE) [WeekEnd]
/*-- Week End
--7->Saturday --8-> Sunday...*/
Running this today will produce this result:
WeekStart WeekEnd
---------- ----------
2018-02-26 2018-03-04
if you have dates in your table, you can use them instead of the GETDATE()

Related

Sum over defined Week limits

I have a rolling date with associated hours. I want to sum the hours over my defined 7-day week range of Saturday to Friday.
So I need to define any date as a week beginning Saturday, week ending Friday and sum over this range.
The table is in the form of:
Date
Day
Hours
2021-06-12
Saturday
3
2021-06-18
Friday
3
2021-06-21
Monday
1
2021-06-22
Tuesday
2
Grouping the above table into Saturday-Friday Week sums.
Saturday
Friday
Total_Hours
2021-06-12
2021-06-18
6
2021-06-19
2021-06-25
3
You can use date functions to get for each date (other than Saturday) the previous Saturday which is the start of the week it belongs too and group by that:
WITH cte AS (
SELECT *, DATEADD(day, -DATEPART(dw, Date) % 7, Date) Saturday
FROM tablename
)
SELECT Saturday,
DATEADD(day, 6, Saturday) Friday,
SUM(Hours) Total_Hours
FROM cte
GROUP BY Saturday
See the demo.
This code works in SQL Server but similar logic and functions can be used for other databases.
You don't have to tie this to datepart() or datename(), which in turn depends on DATEFIRST (alas!).
Instead, you can use date arithmetic. This in turn depends on the fact that 0 date is a Monday. But that is not configurable (as far as I know).
So:
select v.week as saturday, dateadd(day, 6, v.week) as friday,
sum(hours)
from t cross apply
(values (dateadd(day, 7*datediff(week, 0, dateadd(day, 1, t.date)) - 2, 0))
) v(week)
group by v.week
order by v.week;
Here is a db<>fiddle.

Totals by Day of week over a 2 week period for 1 year

Adding the query (so far) and the result....
DECLARE #var_StartDate DATETIME
DECLARE #var_EndDate DATETIME
SET #var_StartDate = '11/25/2017' -- Set the start date
SET #var_EndDate = '11/23/2018'; --Set the end date
SELECT
DATENAME(DW, VTOTALS.APPLYDATE) AS Day,
FORMAT(SUM(TRANSACTIONS), '#,0.') AS Transactions
FROM
VTOTALS
WHERE
APPLYDATE BETWEEN #var_StartDate AND #var_EndDate
GROUP BY
DATENAME(DW, VTOTALS.APPLYDATE)
ORDER BY
CASE
WHEN DATENAME (DW, VTOTALS.APPLYDATE) = 'Sunday' THEN 1
WHEN DATENAME (DW, VTOTALS.APPLYDATE) = 'Monday' THEN 2
WHEN DATENAME (DW, VTOTALS.APPLYDATE) = 'Tuesday' THEN 3
WHEN DATENAME (DW, VTOTALS.APPLYDATE) = 'Wednesday' THEN 4
WHEN DATENAME (DW, VTOTALS.APPLYDATE) = 'Thursday' THEN 5
WHEN DATENAME (DW, VTOTALS.APPLYDATE) = 'Friday' THEN 6
WHEN DATENAME (DW, VTOTALS.APPLYDATE) = 'Saturday' THEN 7
END ASC
Output:
Day Transactions
Sunday 10,697,804
Monday 25,222,976
Tuesday 25,001,258
Wednesday 24,986,845
Thursday 25,039,354
Friday 24,591,728
Saturday 12,087,903
I am looking for transaction totals by day of week over each day of a pay period for a 1 year timeframe. I can get the DOW but want to split into DOW for week 1 and week 2 over the year between 11/25/17 - 11/23/18
Week 1
Sun 1,980
Mon 38,987
Tue 28,132
Wed 30,879
Thu 30,769
Fri 39,902
Sat 41,912
Week 2
Sun 2,280
Mon 37,987
Tue 29,132
Wed 36,879
Thu 39,769
Fri 42,902
Sat 44,912
Any thoughts?
Thanks
You want weeks that start on Sunday, so you can use the mode argument to week. If you just want the values for one year:
select week(dte, 0), sum(total)
from t
where dte >= '2017-01-01' and dte < '2018-01-01' -- or however you define "year"
group by week(dte, 0);
Take the number of days since some given date, and calculate X % 14. This divides the result by 14 and returns the remainder which will be a number in the range 0 through 13. If you want your result to start on a Sunday, then make sure the given date is a Sunday.
create table VTOTALS
(APPLYDATE date,
[TRANSACTIONS] money)
go
set nocount on
declare #Y int = 0
while #Y < 10000
begin
insert into VTOTALS(ApplyDate,Transactions)
values(
DateAdd(day, #Y % 1000,
'2017-01-01T00:00:00.000' ),
(#Y + 314159)%271828 )
set #Y=#Y+1
end
go
DECLARE #var_StartDate DATETIME
DECLARE #var_EndDate DATETIME
SET #var_StartDate = '2017-11-25T00:00:00.000' -- Set the start date
SET #var_EndDate = '2018-11-23T00:00:00.000'; -- Set the end date
with VWeeks as
( select
DateDiff(day,
'1899-12-31T00:00:00.000',
ApplyDate)%14
as ZeroToThirteen,
* from VTOTALS
WHERE
APPLYDATE BETWEEN #var_StartDate AND #var_EndDate )
SELECT
ZeroToThirteen / 7 + 1 as WeekNum,
DateName ( DW, DateAdd ( day,
ZeroToThirteen,
'1899-12-31T00:00:00.000' ) ) as DayName,
FORMAT(SUM(TRANSACTIONS), '#,0.') AS Transactions
FROM
VWeeks
GROUP BY
ZeroToThirteen
ORDER BY
ZeroToThirteen
returns
WeekNum DayName Transactions
----------- ------------------------------ ----------------
1 Sunday 12,307,100
1 Monday 12,307,360
1 Tuesday 12,307,620
1 Wednesday 12,307,880
1 Thursday 12,308,140
1 Friday 12,308,400
1 Saturday 12,308,660
2 Sunday 12,308,920
2 Monday 12,309,180
2 Tuesday 12,309,440
2 Wednesday 12,309,700
2 Thursday 12,309,960
2 Friday 12,310,220
2 Saturday 12,306,840

How to get month value using week value sql server

I want to get month value using week no.
I have week numbers stored in a table with year value.
How to query database to get month value using that week value.
I am using SQL
You can try this:
SELECT DATEPART(m,DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + CAST(t.year as VARCHAR(4))) + (t.week-1), 6))
It depends on how you're classing your week numbers, For example, if we assume that week numbers start on a Monday then we'd have to say that week 1 in 2016 actually started on Monday 28th of December 2015 and finished on Sunday 3rd January 2016. If this is how your week numbers are set up then you can use the method below
Sample Data;
CREATE TABLE #DateTable (WeekNum int, YearNum int)
INSERT INTO #DateTable (WeekNum, YearNum)
VALUES
(1,2016)
,(2,2016)
,(3,2016)
,(4,2016)
,(5,2016)
,(6,2016)
,(7,2016)
We will then cast the week and year into a date, then convert this to a month;
SELECT
WeekNum
,YearNum
,DATEADD(wk, DATEDIFF(wk, 7, '1/1/' + CONVERT(varchar(4),YearNum)) + (WeekNum-1), 7) AS WeekStart
,DATEPART(mm,DATEADD(wk, DATEDIFF(wk, 7, '1/1/' + CONVERT(varchar(4),YearNum)) + (WeekNum-1), 7)) MonthNum
(Edit: updated as source is int)
Gives these results;
WeekNum YearNum WeekStart MonthNum
1 2016 2015-12-28 00:00:00.000 12
2 2016 2016-01-04 00:00:00.000 1
3 2016 2016-01-11 00:00:00.000 1
4 2016 2016-01-18 00:00:00.000 1
5 2016 2016-01-25 00:00:00.000 1
6 2016 2016-02-01 00:00:00.000 2
7 2016 2016-02-08 00:00:00.000 2
You can't go from week number to month because weeks can occur in two different months. For example the 31st Jan 2016 and 1st Feb 2016 are both in week 6.
SELECT DATEPART(WEEK, '2016-01-31')
SELECT DATEPART(WEEK, '2016-02-01')
You can try the query below:
SELECT
[Week],
[Year],
'Output-Month' = MONTH(DATEADD(WEEK, [Week], DATEADD(WEEK, DATEDIFF(WEEK, '19050101', '01/01/' + CAST([Year] AS VARCHAR(4))), '19050101')))
FROM YourTable
1st is to get the 1st day of the year using this:
DATEADD(WEEK, DATEDIFF(WEEK, '19050101', '01/01/' + CAST([Year] AS VARCHAR(4))), '19050101')
2nd is to add your number of week using this:
DATEADD(WEEK, [Week], 'From 1st result')
Last is getting the number of Month using the MONTH function.

week beginning (Monday) for previous day

I want to pull all the data for the week to the previous day.
for example:
if the date was Monday 2016-05-09. I would like the previous Monday 2016-05-02 to Sunday 2016-05-08.
If the date was Tuesday 2016-05-10. I would like the previous Monday 2016-05-09 to Monday 2016-05-09.
I have tried using with no joy.
and (ShiftDate Between DATEADD(wk, 0, DATEADD(DAY, (1-DATEPART(WEEKDAY, GETDATE()-1)), DATEDIFF(dd, 0, GETDATE())))and GETDATE()-1)
You should use this:
and (ShiftDate Between (GETDATE() - 1 - (DATEPART(weekday, GETDATE() -1) + 7 - 2) % 7)
and (GETDATE()-1)
)
Because Sunday is 1 in weekday so you should add 7 then module by 7 to get the different from nearest Monday (2 in weekday) to the previous day.

MSSQL - Getting last 6 weeks returns last 8 weeks

I am having a problem with week numbers. The customers week starts on a Tuesday, so ends on a Monday. So I have done:
Set DateFirst 2
When I then use
DateAdd(ww,#WeeksToShow, Date)
It occasionally gives me 8 weeks of information. I think it is because it goes over to the previous year, but I am not sure how to fix it.
If I do:
(DatePart(dy,Date) / 7) - #WeeksToShow
Then it works better, but obviously doesn't work going through to previous years as it just goes to minus figures.
Edit:
My currently SQL (If it helps at all without any data)
Set DateFirst 2
Select
DATEPART(yyyy,SessionDate) as YearNo,
DATEPART(ww,SessionDate) as WeekNo,
DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate +SessionTime AS DATE)) [WeekStart],
DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE)) [WeekEnd],
DateName(dw,DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE))) as WeekEndName,
Case when #ConsolidateSites = 1 then 0 else SiteNo end as SiteNo,
Case when #ConsolidateSites = 1 then 'All' else CfgSites.Name end as SiteName,
GroupNo,
GroupName,
DeptNo,
DeptName,
SDeptNo,
SDeptName,
PluNo,
PluDescription,
SUM(Qty) as SalesQty,
SUM(Value) as SalesValue
From
PluSalesExtended
Left Join
CfgSites on PluSalesExtended.SiteNo = CfgSites.No
Where
Exists (Select Descendant from DescendantSites where Parent in (#SiteNo) and Descendant = PluSalesExtended.SiteNo)
AND (DATEPART(WW,SessionDate + SessionTime) !=DATEPART(WW,GETDATE()))
AND SessionDate + SessionTime between DATEADD(ww,#NumberOfWeeks * -1,#StartingDate) and #StartingDate
AND TermNo = 0
AND PluEntryType <> 4
Group by
DATEPART(yyyy,SessionDate),
DATEPART(ww,SessionDate),
DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate +SessionTime AS DATE)),
DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE)),
Case when #ConsolidateSites = 1 then 0 else SiteNo end,
Case when #ConsolidateSites = 1 then 'All' else CfgSites.Name end,
GroupNo,
GroupName,
DeptNo,
DeptName,
SDeptNo,
SDeptName,
PluNo,
PluDescription
order by WeekEnd
There are two issues here, the first is that I suspect you are defining 8 weeks of data as having 8 different values for DATEPART(WEEK, in which case you can replicate the root cause of the issue by looking at what ISO would define as the first week of 2015:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(WEEK, Date)
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which gives:
Date Week
-----------------
2014-12-29 52
2014-12-30 53
2014-12-31 53
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
So although you only have 7 days, you have 3 different week numbers. The problem is that DATEPART(WEEK is quite a simplistic function, and will simply return the number of week boundaries passed since the first day of the year, a better function would be ISO_WEEK since this takes into account year boundaries nicely:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, Date)
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which gives:
Date Week
-----------------
2014-12-29 1
2014-12-30 1
2014-12-31 1
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
The problem is, that this does not take into account that the week starts on Tuesday, since the ISO week runs Monday to Sunday, you could adapt your usage slightly to get the week number of the day before:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date))
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which would give:
Date Week
-----------------
2014-12-29 52
2014-12-30 1
2014-12-31 1
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
So Monday the 29th December is now recognized as the previous week. The problem is that there is no ISO_YEAR built in function, so you will need to define your own. This is a fairly trivial function, even so I almost never create scalar functions because they perform terribly, instead I use an inline table valued function, so for this I would use:
CREATE FUNCTION dbo.ISOYear (#Date DATETIME)
RETURNS TABLE
AS
RETURN
( SELECT IsoYear = DATEPART(YEAR, #Date) +
CASE
-- Special cases: Jan 1-3 may belong to the previous year
WHEN (DATEPART(MONTH, #Date) = 1 AND DATEPART(ISO_WEEK, #Date) > 50) THEN -1
-- Special case: Dec 29-31 may belong to the next year
WHEN (DATEPART(MONTH, #Date) = 12 AND DATEPART(ISO_WEEK, #Date) < 45) THEN 1
ELSE 0
END
);
Which just requires a subquery to be used, but the extra typing is worth it in terms of performance:
SET DATEFIRST 2;
SELECT Date,
Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
Year = (SELECT ISOYear FROM dbo.ISOYear(DATEADD(DAY, -1, Date)))
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Or you can use CROSS APPLY:
SET DATEFIRST 2;
SELECT Date,
Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
Year = y.ISOYear
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date)
CROSS APPLY dbo.ISOYear(d.Date) y;
Which gives:
Date Week Year
---------------------------
2014-12-29 52 2014
2014-12-30 1 2015
2014-12-31 1 2015
2015-01-01 1 2015
2015-01-02 1 2015
2015-01-03 1 2015
2015-01-04 1 2015
Even with this method, by simply getting a date 6 weeks ago you sill still end up with 7 weeks if the date you are using is not a Tuesday, because you will have 5 full weeks, and a part week at the start and a part week at the end, this is the second issue. So you need to make sure your start date is a Tuesday. The following will get you Tuesday of 7 weeks ago:
SELECT CAST(DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), DATEADD(WEEK, -6, GETDATE())) AS DATE);
The logic of this is explained better in this answer, the following is the part that will get the start of the week (based on your datefirst settings):
SELECT DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), GETDATE());
Then all I have done is substitute the second GETDATE() with DATEADD(WEEK, -6, GETDATE()) so that it is getting the start of the week 6 weeks ago, then there is just a cast to date to remove the time element from it.
This will get you current week + 5 previous weeks starting tuesday:
WHERE dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) <= yourdatecolumn
This will show examples:
DECLARE #wks int = 6 -- Weeks To Show
SELECT
dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) tuesday5weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - 5, 1) tuesday6weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - 6, 1) tuesday7weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - #wks + 1, 1) tuesdaydynamicweeksago
Result:
tuesday5weeksago tuesday6weeksago tuesday7weeksago tuesdaydynamicweeksago
2015-01-27 2015-01-20 2015-01-13 2015-01-20