Issues when comparing dates in IIF in SSRS matrix - sql-server

Hi I'm new to ssrs and am attempting to make a report which lists the "Utilisation" percentage of people based on the amount of tasks they have completed and the amount of hours they are working that day, these two values are pulled in by a sql query and "Utilisation" is a calculated field within the report.
This is set up in a matrix format with [date] as the column grouping and [name] as the row grouping, the past year of "Utilisation" is calculated but only the past week from the chosen MaxDate parameter is unhidden in the actual preview.
My problem comes from attempting to calculate the average Utilisation of each person for the past week from the MaxDate parameter. I hope to do the past month aswell.
It just seems like all the code I try, at best just produces #Error when the IFF is true.
Here are some of the things I've tried:
=Sum(IIF(DateDiff("d",Fields!Date.Value, Parameters!MaxDate.Value) < 7, Sum(Fields!Utilisation.Value), ""))
=IIF(DateDiff("d",CDate(Fields!Date.Value), CDate(Parameters!MaxDate.Value)) < 7, Sum(Fields!Utilisation.Value), "")
=IIF(DateAdd("d",-7, Parameters!MaxDate.Value) <= Fields!Date.Value, Sum(Fields!Utilisation.Value), "")
There have been alot more I've tried, these just calculate the total but I would use a count to find the average once I get this working.
My best guess at what's happening is that the IIF statement's only looking at the first Date in the matrix and then comparing that date to see if the conditions true, because if I do:
=IIF(Fields!Date.Value >= "2000/09/20", Sum(Fields!Utilisation.Value), "")
It returns the total of ALL of the Utilisation fields because the first date for each row is after "2000/09/20".
Does anyone have any suggestions?
Thank you
UPDATE:
Something like:
=SUM(IIF(IsNothing(Fields!Date.Value), 0, IIF(DateDiff("d", Fields!Date.Value, Parameters!MaxDate.Value) < 7, 1, 0)), "name")
"works", in that it provides a correct count of the amount of days with a non null utilisation in the past week but as soon as you turn that 1 into a field it errors.
I tried making a work around by making the sql decide whether the day is in the past week or month via W and M codes that are added in the statement. I did this incase the problem was with the date field but even when using the code it doesn't seem to really work. Is this some fundamental limitation with SSRS or am I just consistently fucking up.
=SUM(IIF(IsNothing(Fields!Date.Value), 0, IIF(Fields!Code.Value = "W" , (Fields!TaskTime.Value /Fields!AvailableHours.Value), 0)))
=SUM(IIF(IsNothing(Fields!Date.Value), 0, IIF(Fields!Code.Value = "W" , SUM(Fields!Utilisation.Value), 0)))
=Sum(IIF(Fields!Code.Value = "W", SUM(Fields!TaskTime.Value), 0))
UPDATE
Okay so:
=(IIF(IsNothing(Fields!AvailableHours.Value),"" , SUM(SUM(Fields!TaskTime.Value / Fields!AvailableHours.Value)) / (SUM(Fields!AvailableHours.Value)/7)))
will give me a yearly average from the whole 365 day dataset but for some reason
=(IIF(IsNothing(Fields!WeekCode.Value),"" , SUM(SUM(Fields!TaskTime.Value / Fields!AvailableHours.Value)) / (SUM(Fields!AvailableHours.Value)/7)))
where only the ones within the week of the chosen date are marked with a week code, the rest are applied null, wont work???I don't understand whats happening or why there seem to be these weird limits.

Ok so I didn't find an exact solution to this but I did find a workaround. I guess the problem likely came from using sum on calculated fields within ssrs, to work around this in a arguably inefficient way, within the sql I created 2 more columns that were calculated, weekUtilisation and MonthUtilisation, If the row's date was within a week of the date variable the utilisation was calculated there else there was a null and the same for the monthUtilisation but... within a month of the variable. This allowed me to just do sum(WeekUtilisation) and sum(MonthUtilisation) within SSRS which actually worked and then divide by count of the amount of non nulls in a row this gave me the average I wanted. Doing it within the sql is likely a faster solution anyway.

I've found that the #Error code means that your code was correct and able to be compiled but produced an error. This is usually caused by math equations doing things like dividing by zero or trying to calculate with ambiguous data types.
Try casting all of your Fields and Parameters to the data type that is expected by the comparisons.
For example where you do:
IIF(DateDiff("d", Fields!Date.Value, Parameters!MaxDate.Value) < 7, 1, 0)
do
IIF(DateDiff("d", CDATE(Fields!Date.Value), CDATE(Parameters!MaxDate.Value)) < 7, 1, 0)
and where you have
SUM(SUM(Fields!TaskTime.Value / Fields!AvailableHours.Value))
not sure why you would SUM twice but
SUM(CINT(Fields!TaskTime.Value) / CINT(Fields!AvailableHours.Value))
and make sure those values you are dividing by aren't zero.

Related

How do I calculate Turnaround rate (%) in SSRS?

I am creating a SSRS report and one of the requirements of the report is to display ‘Turnaround Rate’ which is supposed to contain values in percentage.
Some of the columns from my dataset are like:-
DateReceived
DateCompleted
CompleteTurnaround
TurnaroundVolume
MaximumTurnaroundDays
TurnaroundInMonth
TurnaroundInStandard
I’ve done an extensive research on the topic and haven’t found a solution yet. Also absolutely lost here and would really appreciate any help with this problem.
Thanks.
I think a Turnaround Rate would be based upon records that were completed within the Standard amount of time as indicated in the TurnaroundInStandard column.
Assuming there's one record per and your grouping them, it should be the records that were complete within the standard amount of time (TurnaroundInStandard = 1 or Y, depending on the field) divided by the number of total number of ones that are complete (CompleteTurnaround = 1 or Y). If so, then your expression would be:
=SUM(IIF(Fields!CompleteTurnaround.Value = "Y", 1, 0))
/
SUM(IIF(Fields!TurnaroundInStandard.Value = "Y", 1, 0))

MS Excel 2010 Count unique values with multiple criteria and EDATE

I am trying to get a count of all Unique values listed in Col A, by state and within a date range, for example all records up to the end of April 2018.
I am able to get the count of Unique values by state (result is 2) with the below formula:
{=SUMPRODUCT(1*(FREQUENCY(IF($C$2:$C$14=F10,MATCH($A$2:$A$14,$A$2:$A$14,0)),ROW($A$2:$A$14)-ROW($A$2))>0))}
but I am unable to get the IF function to work with EDATE. I tried the following but I'm getting 0 as the result. The result should be 1.
{=SUMPRODUCT(1*(FREQUENCY(IF(D2:D14="<"&EDATE(G1,1),IF($C$2:$C$14=F10,MATCH($A$2:$A$14,$A$2:$A$14,0))),ROW($A$2:$A$14)-ROW($A$2))>0))}
I am unable to use Pivot as I need to include date range filter. Could someone please look at my code and tell me what I'm doing wrong? I am using CSE with my formulas. Thankyou!
I managed to work it out. EDATE wasn't working so I entered the Month date in cell:G1 then referenced it in the IF formula using "<=" eg: IF(D2:D14<=G1).
Whole array formula is:
`{=SUMPRODUCT(1*(FREQUENCY(IF(D2:D14<=G1,IF($C$2:$C$14=F10,MATCH($A$2:$A$14,$A$2:$A$14,0))),ROW($A$2:$A$14)-ROW($A$2))>0))}
I now receive the correct count of 1, though I have to ensure I have entered the last day of the Month in G1. State is referenced in F10 and count of unique values is in Column A.
My full data set is sourced from multiple documents over 5000 rows each and growing daily so my workbook is quite slow to calculate over 1000 array formulas... but it works!
If anyone knows of a faster (possibly non-array) formula, I would appreciate the advice! Thanks!

SSRS: Hour() for 24:00

I was using Hour(Fields!tempo.Value) for get the hour from a field (tempo). The problem came when I got for first time "24:00" and the report shows the '#error'.
The description in 'Hour' function said:
Returns an Integer value from 0 through 23 representing the hour of
the day
So, I changed the expression to
=IIf(Fields!tempo.Value = "24:00", 0, Hour(Fields!tempo.Value))
but yet I get the #error. Then I tried:
=IIf(Fields!tempo.Value = "24:00", 0, 1)
and correctly I get "0" for 24:00 values and "1" for the rest.
I don't understand why Hour() won't work under IIf().
Maybe exist some better workaround for this case and I don't know it.
Thanks in advances
EDIT:
The idea is get all events which started between 2 hours every day (for filter events from the morning, afternoon and night):
=IIf(Hour(Fields!tempo.Value) >= 22 Or Hour(Fields!tempo.Value) <= 6, SHOWTHIS, Nothing)
if you don't need to perform operations with the hour you can work with strings to get the hour, also if your dataset returns a string this is the simplest solution (IMO).
Try using this expression:
=IIF(LEFT(Fields!tempo.Value,2)="24","0",REPLACE(LEFT(Fields!tempo.Value,2),":",""))
If you still want to get the hour using HOUR function you have to validate twice your field, in the IIF and inside the HOUR function:
=IIF(Fields!tempo.Value="24:00",
0,
HOUR(IIF(Fields!tempo.Value="24:00","0:00",Fields!tempo.Value))
)
Let me know if this helps.

Difference in performance in SQL

I have a date column on SQL Server table called dd.
dd
---------------------------
10-01-2015 00:00:00.000
22-05-2015 10:22:32.521
27-05-2015 12:30:48.310
24-12-2014 09:51:11.728
27-05-2015 02:05:40.775
....
I need to retrieve all rows where dd value is from the last 24 hours.
I found 3 options for filtering to get the result needed:
1. `dd >= getdate() - 1`
2. `dd >= dateadd(day, -1, getdate())
3. `dateadd(day, 1, dd) >= getdate()
My questions are:
Are all the 3 options will retrieve all rows I need?
If so what is the difference between them?
dd >= getdate() - 1
This is something like a hack, but it works, but sometimes it can lead to errors(http://www.devx.com/dbzone/Article/34594/0/page/2).
dd >= dateadd(day, -1, getdate())
This is standard way of doing things.
dateadd(day, 1, dd) >= getdate()
This will also work but there is one NO. It will not use index if any index is created on that column. Because it is not a Search Argument(What makes a SQL statement sargable?). When you apply an expression to some column it becomes non SARG and will not use any index.
All 3 version will produce same result, but first is hack and in some cases will lead to bug. Third will not use index. So it is obvious that one should stick on option 2.
First two are exactly like Giorgi said, but on the third one your Index Seek will become Index Scan. SQL Server will still use that index but it is no longer able to jump to specific record but instead it has to scan it to find what it need.
For the purpose of demonstration I selected the table that had DATETIME column indexed and only selected that column to avoid any key lookups, and to keep plan simple.
Also take a look at reads on the table and estimated vs returned row count. As soon as you wrapped the column in a function it is not able to estimate correct number of rows which will cause large performance issues when queries become more complex.

Are these two pieces of SQL code the same?

I'm working with a bit of an older code base where conciseness is not found in many places.
One piece of code we are constantly using in the database is to determine if two dates are within the same program year. For instance, Program Year 2011 begins on July 1st, 2011 and ends on July 1st, 2012(or technically the day before)
The usual way I see that this problem is solved is by using this kind of code:
if Month(#EnrollmentDate)>=7 begin
set #StartDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)))
set #EndDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)+1))
end else begin
set #StartDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)-1))
set #EndDate='07/01/'+LTRIM(RTRIM(Year(#EnrollmentDate)))
end
...
where (ENROLLMENTDATE >= #StartDate and ENROLLMENTDATE < #EndDate)
I recently happened to have to solve this problem and the instant thing that popped in my head was something much more concise:
where year(dateadd(mm,-6,ENROLLMENTDATE)) = year(dateadd(mm,-6,#EnrollmentDate))'
Before I go introducing new bugs into a system that "just works", I'd like to ask SO about this. Are these two pieces of code exactly the same? Will they always give the same output(assuming valid dates)?
the problem I see is that, depending on the optimizer, your solution (that looks better) may not use an index defined on ENROLLMENTDATE since you're doing operations on it, while the original solution would. If there are no indexes on that field, then I don't see an issue
An even easier way to handle this situation is to create a calendar table with a column for the program year. Then there is no logic at all, you just query the values and compare them:
if
(select ProgramYear from dbo.Calendar where BaseDate = #StartDate) =
(select ProgramYear from dbo.Calendar where BaseDate = #EndDate)
begin
-- do something
end
There are many posts on this site about creating calendar tables and using them for many different purposes. In my experience, using a table in this way is always clearer and more maintainable than creating formulas in code.
As it happens, December has 31 days, so no matter how many months you need to subtract, you will always be able to align the resulting date range with a whole year, and therefore your expression will always be true whenever the original one was, even in the general case for an enrolment year starting on other dates.
I once used a dialect of SQL with a range of date manipulation functions that made this slightly easier than string twiddling, something like this:
WHERE enrolmentdate >= #YearBeg(:enrolmentdate + 6 MONTHS) - 6 MONTHS
AND enrolmentdate < #YearBeg(:enrolmentdate + 6 MONTHS) + 6 MONTHS

Resources