How to get every Monday out of a Date - sql

I need some help to understand a certain line in a code. The code takes the turnovers of every Monday in the year 2010 and at the last line in summarizes all the turnovers to one.
Here is the code:
SELECT
CASE
WHEN GROUPING (DATUM) = 1 THEN 'Gesamtumsatz'
ELSE CAST (DATUM AS VARCHAR (40))
END AS MONTAGSDATEN,
AVG (VERKAUFSWERT * VERKAUFSMENGE) as UMSATZ
FROM Data_Star_Awesome.dbo.VERKAUFSFAKTEN vk
INNER JOIN DIMDATUM dimD on vk.DATUMID=dimD.DATUMID
WHERE DATEDIFF(dd,0, DATUM)%7=0
AND JAHR = 2010
GROUP BY ROLLUP (DATUM)
The problematic line I don't understand is the following:
WHERE DATEDIFF(dd,0, DATUM)%7=0
What I know is that it takes the days out of the date variable but I don't get the %7=0 part. The DATEDIFF function should give back all the days. Are these days saved in the % the placeholder? And how does it get all the Mondays by using the 7=0?
It would be great if someone could help me out.
Thanks a lot :)

Modulo or % operator is the same as in a lot of programming languages. It returns the remainder after the division.
The DATEDIFF function takes two dates and returns the difference in a specified datepart, which in your query is the days represented by dd.
Also 0 as date converts to 1/1/1900 which happens to be a Monday. So your query is calculating the days between 1/1/1900 and the DATUM field in days and if its Mod is 0 then DATUM is Monday.

You could simply say:
datename(weekday,<datetime-value>)
Which will return 'Monday', 'Tuesday', 'Wednesday', etc. The problem with this approach is that the returned value is localized. If the SQL server's language is changed, your test for 'Monday' will fail.
This expression will always work:
( ##datefirst + ( datepart(weekday,today) - 1 ) ) % 7
It evaluates to 1-7, where Monday is always 1 and Sunday is always 7, regardless of culture/language settings or the current value of ##datefirst, as set by set datefirst.
We can then convert this into this discriminant function, yielding 1 or 0 to indicate whether or not the date is Monday:
case ( ##datefirst + ( datepart(weekday,today) - 1 ) ) % 7 when 1 then 1 else 0 end

Related

How to get the exact year difference in SQL

I need a simple way to find the exact year difference between two dates.
For example between 01.11.2013 and 30.10.2019. In this case, it should be 5 years because current date has not reached 01.11 yet. But if it is between 29.10.2013 and 30.10.2019 then it should be 6 years.
Let assume these are birthday and current days. It's similar.
I've tried to get the result with the following code:
select datediff(year,20131101,20191030)
It is giving me 6 instead of 5. The closest solution I've found is:
select datediff(day,20131101,20191030)/365
But as we know there could be 1 or 2 leap years in this period and the result is again not exactly what I expect. Neither when we divide with 365 nor 366.
It is not necessary using datediff. I wonder if there is some simple way to present it or some stored function to do this for which existing I did't know.
You can take the year difference and then subtract 1 if necessary:
select (datediff(year, val1, val2) -
(case when month(val1) < month(val2) then 0
when month(val1) > month(val2) then 1
when day(val1) <= day(val2) then 0
else 1
end)
) as diff_years
You can try datediff Month / 12.
Declare #date1 Datetime
Declare #date2 Datetime
set #date1='2013-11-01 23:59:59'
set #date2='2019-10-30 00:00:00'
(select (datediff(HOUR, #date1, #date2)/24/365 ) as diff_years)

SSRS. Workday Function

I'm trying to convert the below Excel formula into SSRS but having looked around I cannot seem to find a solution. I can calculate the number of working days between two dates but what I'm trying to do is add on a number of working days to a date. Essentially I don't have the 2nd date.
I guess it would be something along the lines of the DATEADD function?
=WORKDAY($A1,B$1)
Hope someone can help
Many thanks
Here is a tsql solution to add X Business Days to a date.
declare #calendar as table (theDate date, dayOfWeek varchar (10));
declare #startDate as date = '20170704';
declare #businessDaysToAdd as integer = 10;
insert into #calendar
select theDate
, datename(dw, theDate) dow
from
dbo.dateTable('20170701', '20170720') ;
with temp as (
select theDate
, dayOfWeek
, rank() over (order by theDate) theRank
from #calendar
where theDate > #startDate
and dayOfWeek not in ('Saturday', 'Sunday')
)
select * from temp
where theRank = #businessDaysToAdd;
Notes
dbo.DateTable is a table valued function that just happens to exist in the database I was using. In real life, you might have an actual calendar table of some sort.
This example does not include holidays.
This is only the start of the answer to the posted question. It only solves the problem of Essentially I don't have the 2nd date.
Type this into the expression for the textbox. (From SSRS 2008 Datediff for Working Days)
=(DateDiff(DateInterval.day,Parameters!STARTDATE.Value,Parameters!ENDDATE.Value)+1)
-(DateDiff(DateInterval.WeekOfYear,Parameters!STARTDATE.Value,Parameters!ENDDATE.Value)*2)
-(iif(Weekday(Parameters!STARTDATE.Value) = 7,1,0)
-(iif(Weekday(Parameters!ENDDATE.Value) = 6,1,0))-1)
Ok after much perseverance I managed to get what I wanted in both TSQL and SSRS. My objective was to measure Agent productivity so I didn’t want to count the weekend and this would be unfair. If a date fell on a weekend then I wanted it to jump to a Monday. Likewise if adding number of days onto a date went over a weekend in the future then I needed the incremented date to reflect this. For the end user (In SSRS) I wanted a leading edge (Like an Upside down triangle) so that if the date + number working days was in the future then set to NULL, showing a zero would look like no productivity which is incorrect.
First TSQL - My base query started with the following SO thread but after trying many of the options I was finding when the date fell on a Saturday or Sunday the solution did not work for me (I was unable to create functions due to permissions). However tweaking the below got me there and I dealt with Sunday specifically
Add business days to date in SQL without loops
SELECT
,DATEADD(WEEKDAY, (/*Your Working Days*//5)*7+(/*Your Working Days*/ % 5) +
(CASE WHEN DATEPART(WEEKDAY,/*Your Date*/) <>7 AND DATEPART(WEEKDAY,/*Your Date*/) + (/*Your Working Days*/ % 5) >5 THEN 2
WHEN DATEPART(WEEKDAY,/*Your Date*/) = 7 AND DATEPART(WEEKDAY,/*Your Date*/) + (/*Your Working Days*/ % 5) >5 THEN 1 ELSE 0 END), /*Your Date*/) AS [IncrementedDate]
FROM /*YourTable*/
Then for SSRS - The 2 key points here is that TSQL will divide as an integer if the source number is an integer so this needs to be handled in SSRS and secondly you need to set the first week day to Monday as part of the expression.
I put this expression into a Matrix with Date Created being my Row Group and Contact Working Days being my Column Group.
=DATEADD("W",(INT(ReportItems!ContactWorkingDays.Value/5))*7+(ReportItems!ContactWorkingDays.Value MOD 5) + IIF(DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) <> 7 AND (DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) + (ReportItems!ContactWorkingDays.Value MOD 5) >5),2,IIF(DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) = 7 AND (DATEPART("W",ReportItems!DateCreated.Value,FirstDayOfWeek.Monday) + (ReportItems!ContactWorkingDays.Value MOD 5) >5),1,0)),ReportItems!DateCreated.Value)
This does not include holidays - I'm not too bothered at this stage and that is for a rainy day! :)

return week number based on date

I am new to T-SQL and needed urgent assistance here.
I am trying to get the week number from a given date.
I understand that there is a build in function for it but the value return is not exactly what I wanted.
For e.g., by using select datepart(wk, '2013-01-07'), it would return me '2'.. but the actually fact is it should return '1' instead of '2'.
Any ideas how to correct this issue?
You can use dy datepart specifier to get dayOfYear number and divide it by 7:
select (datepart(dy, '2013-01-05') - 1) / 7 + 1;
Working DEMO.
Try this
SELECT DATEPART(WEEK,GETDATE())
This depends on hop you define the first week. Does it always start on the same weekday? or does it always start on the first of January? If you want it to always start on the same weekday, then use Set datefirst to tell T-SQL what weekdaty you want to define as the start of the week. If you want it to always start on Jan 1, then just use day of year instead of week, subtract 1, integer divide by 7 and add 1.
declare #dat DateTime = getdate()
Select Select (datepart(dy, #dat)-1) / 7 + 1
Although going from memory, I believe the ISO standard for the first week of the year is the week in the year that the first Thursday of the year is in. This would possibly explain why the built in function gives a result different to that you require.

What is happening in this query?

I am trying to get the last of month, and in order to that i have written the following, to calculate the no. of days between today and the last date.
select datediff(DAY,GETDATE(),dateadd(m,1,getdate()))-GETDATE()
the bold part gives me the no. of days between today and a month from today, say 30 or 31. and then I am subtracting today's date from 30 or 31, which is " -getdate() "
The output for the above query is
1786-06-06 11:44:30.540
Could you please explain what is happening in the query? I am not looking for a solution, I would like to know how is SQL-Server interpreting the query.
Thanks. :)
The bold part of the expressions does not return a date, it returns a number of days:
31
Convert that to a datetime:
SELECT CONVERT(DATETIME, 31);
This is 31 days after day 0 (1900-01-01):
1900-02-01
Now, subtract GETDATE() as an integer (41512 days after day 0):
SELECT 31 - 41512 = -41481
Now add -41481 days to day 0:
SELECT DATEADD(DAY, -41481, 0);
-- or
SELECT DATEADD(DAY, -41481, '19000101');
Or:
SELECT CONVERT(DATETIME, 31 - CONVERT(INT, GETDATE()));
Now, I strongly recommend a couple of things:
Don't use implicit date math. #date_var_or_col - 1 for example fails with new data types like DATE and DATETIME2.
Don't use shorthand like m. If you mean MONTH, just take the massive productivity hit and type out MONTH. To see why, tell me if this provides the results you expect:
SELECT DATEPART(y, GETDATE()), DATEPART(w, GETDATE());
I am subtracting today's date from 30 or 31, which is " -getdate() "
Sounds like you understand exactly what is happening, but maybe don't understand the results.
You are implicitly converting GETDATE() to a number, which represents the number of days (and fractional days) since 1/1/1900 12:00:00 AM
When you "subtract" GETDATE() (41,511 as of 8/27/2013) from 30 or 31 you get an answer of -41,480, or 41,480 days before 1/1/1900, which would be about 6/6/1786 (plus or minus a few hours for the fractional part).

Sliding Week Comparison

I want to compare data from the current week (1 through 52) to the data from two weeks prior. I need to make sure that when the new-year boundary is crossed, the comparison keeps working. I have a working predicate, like this:
WHERE ( DATEPART(ww,MA.DateOpen) + 1 ) % 52 = DATEPART(ww,#ImportDate) - 1
The above logic works, but it does not account for proximate years. In other words, unwanted data from week 'X' of all prior years will be included in the comparison. So the predicate must be expanded to account for years, which in turn requires handling the new year boundary: week 1 of 2012 should be compared against week 51 of 2011.
How can this be done without a verbose looking predicate?
update:
This question is complicated by the need for "week of year" to be treated as Tuesday through Tuesday. My current "correct" attempt is embodied in the [VerboseCheck] case below.
SET DATEFIRST 2
DECLARE #ImportDate date = '2011-1-4'
DECLARE #DateOpen date = '2010-12-20'
select #ImportDate,
YEAR(#DateOpen),
DATEPART(ww, #DateOpen),
YEAR(DATEADD(dd,-14,#ImportDate)),
DATEPART(ww,DATEADD(dd,-14,#ImportDate)),
CASE WHEN
YEAR(#DateOpen) + DATEPART(ww, #DateOpen) =
YEAR(DATEADD(dd,-14,#ImportDate)) + DATEPART(ww,DATEADD(dd,-14,#ImportDate))
THEN 1 ELSE 0 END [VerboseCheck],
CASE WHEN DATEDIFF (ww, #DateOpen, #ImportDate) =2
THEN 1 ELSE 0 END [SimpleCheck]
The [SimpleCheck] would be perfect, but it gives a different answer than [VerboseCheck]. If I advance #DateOpen one more day, then the two give the same answer. This suggests that both are not honoring the DATEFIRST evaluation in the same way.
Seems like DateDiff would be best used here. However as you noted DATEFIRST is indeed not respected.
So we just add Itzik Ben-Gan's solution and we get
WHERE DATEDIFF (ww,
DATEADD( day, -##DATEFIRST , #DateOpen),
DATEADD( day, -##DATEFIRST , #ImportDate)
) =2
why not just DATEADD('dd', -14, DateOpen)?
Would something like the following work to compare the years?
WHERE ( DATEPART(ww,MA.DateOpen) + 1 ) % 52 = DATEPART(ww,#ImportDate) - 1
AND YEAR(MA.DateOpen)=YEAR(DATEADD(d, -14, #ImportDate))