Sliding Week Comparison - sql

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))

Related

Two columns with dates (one any day of week, another one WEEK ENDING DATE (SATURDAY) BASED ON 1st column)

I have such a situation.
I need to have 2 columns 1) Is just pull data from a table (just as it is) r.[RCLDTE] (Day of week)
and 2 column) I need to basically look at the first column and make it Saturday of that week.
SELECT r.[RCLDTE] AS 'Day of Week'
,r.[RCLDTE] AS 'Week Ending Day (Saturday)'
Before what I was doing at similar projects I just used this code and added to WHERE statement.
WHERE CONVERT(DATE, CONVERT(CHAR(8), r.[RCLDTE] )) = cast(DATEADD(dd, DATEPART(DW,GETDATE())*-1, GETDATE()) as date)
This code was changing the dates column to Saturday.
However, here I have a different situation. I need 2 columns 1) as it is and 2) where dates will be Saturdays of the week from r.[RCLDTE] column , as a result from the way how I understand I cannot use WHERE statement because it will affect both columns.
Does someone know how I can leave 1st column as it is and 2nd a column of Saturday.
Please let me know.
Thanks.
To avoid issues when someone changes either DATEFIRST or LANGUAGE settings, you can use this. Also, given that you are storing dates in a numeric column for some reason (you really should provide feedback to whoever owns the system so they can fix it), we have to first try to convert those values to a date (they may not all be valid, which is one of the problems with using the wrong data type):
;WITH t AS
(
SELECT *, ProperDate = CASE WHEN ISDATE(CONVERT(char(8), RCLDTE)) = 1
THEN CONVERT(date, CONVERT(char(8), RCLDTE)) END
FROM dbo.tablename
)
SELECT [Language] = ##language, [Datefirst] = ##datefirst,
RCLDTE = CASE WHEN ProperDate IS NULL THEN RCLDTE END,
[Day of Week] = ProperDate,
[Saturday] = DATEADD
(
DAY,
6 - ((DATEPART(WEEKDAY, ProperDate) + ##DATEFIRST - 1) % 7),
ProperDate
)
FROM t;
Updated db<>fiddle that also demonstrates the handling of garbage data and a version of SQL Server so old that TRY_CONVERT() didn't exist yet (at least 12 years ago).
here is one way :
select
r.RCLDTE AS 'Day of Week'
, dateadd(day, 7 - datepart(weekday, r.RCLDTE) , r.RCLDTE)
from tablename r
db<>fiddle here

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! :)

Get the actual month difference between two date

I working with strange queries in SQL, I want to find the actual month difference between two dates, for example
StartDate = '1-1-2013'
EndDate = '4-30-2013'
Here I want result to be 4 not 3
select datediff(mm, '1-1-2013', '4-30-2013')
This query will provide me result 3 but actual result is 4. Can anyone help me on this?
Not quite sure if this helps but here's my stab at it:
declare
#date1 datetime = '2013-01-01',
#date2 datetime = '2013-04-30'
select Cast(Round(Cast(DATEDIFF(DD,#date1, #date2) as decimal(5,2)) / 30, 1) as int) as Months
What you're asking isn't as simple as it first appears. One obvious way would be to add one day to your end date before doing the datediff. This would then be doing 1 Jan to 1 May which would be reported as four months.
However you need to consider if there's any tolerances; for example, should 1 Jan to 29 Apr be considered four months, or is that still three months? Obviously this will depend heavily on the context in which you are using these dates.
Please try to add 01-01-2013 and 04-30-2013 instead of what you added here
So query will be as below
select datediff(mm, '1-1-2013', '4-30-2013')
Thanks
Vasanthan
As others have pointed out, the result is absolutely correct: 3 months and 29 days.
You can of course check if the date in the end date is the last date of the month and make an adjustment to produce the desired result:
DECLARE #START DATETIME, #END DATETIME
SELECT #START = '2014-01-01', #END = '2014-04-30'
SELECT #START, #END
SELECT DATEDIFF(MONTH, #START, CASE WHEN MONTH(DATEADD(DAY, 1, #END)) > MONTH(#END) THEN DATEADD(DAY, +1, #END) ELSE #END END)
Not sure about the performance of said example (you're free to experiment with similar ideas), but what it does is add the last missing day to produce the 4 month difference whenever the end date represents the last day of that month.
Now, I agree with the others here that this is a weird thing to do, but if this is what your case requires, then so be it. We can't really comment on your business / programming specific needs here. :)

How to get every Monday out of a Date

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

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.