SSRS Expression Evaluation Issue - reporting-services

I'm having an issue with expressions within reports. I'm coloring the background of a textbox within a table depending on the value within it. The text in the field relates to backups for a SQL Server. The value is either a date or the text "Not Yet Taken". If the date is more than 2 days old, I want the background to be yellow. If its more than a week old or if the date value is "Not Yet Taken", I want the background to be red. Otherwise, it'll be green.
The problem I've been having since I started with reports for SSRS (a few weeks ago) is that my expressions seem to get fully evaluated. An IF statement will have both its true and false values evaluated even though only one of them will be used.
This becomes a problem because "Not Yet Taken" is clearly not a date and to work with the dates I need to convert the date string into a date. Here is the code I have currently:
=IIF(Fields!LastBackUpTaken.Value = "Not Yet Taken","Red", IIF( IsDate(Fields!LastBackUpTaken.Value) = true,
IIF( CDate(Fields!LastBackUpTaken.Value).AddDays(Parameters!DaysTillExpiry.Value).CompareTo(NOW()) = 1,
"GreenYellow",
IIF( CDate(Fields!LastBackUpTaken.Value).AddDays(7).CompareTo(NOW()) = 1, "Yellow", "Red")),
"Red"))
So basically, the expression reads "If LastBackUpTaken.Value = "Not Yet Taken", return the color Red. If it isn't "Not Yet Taken", check to see if the string is a date. If it isn't a date, return the color Red. If it is a date do calculations and return the appropriate color.
This expressions works for all the text fields that don't have "Not Yet Taken" as its text. For the fields that do have "Not Yet Taken" as its text do not have any color set.
EDIT: I also get a conversion error that I forgot to mention, whenever the text is "Not Yet Taken"
Any ideas?

Write a VB function to return the color string in the Code Tab of the Report Properties. Here you can use language constructs you are comfortable with (case statements, regular if statements, etc.). Logic with be easier to read back as well.
Public Function GetBackgroundColor(ByVal DateString as String) As String
'plain old vb syntax here
End Function
In the expression for the background color property:
=Code.GetBackgroundColor(Fields!LastBackUpTaken.Value)

Related

Row visibility expression using ReportItem collection not working

This is major edit from the previous version of this question, which would hold little of value for future readers anyway.
I have a report where I want to hide certain rows depending on the data in certain fields, but also be able to override this based on a parameter value.
So for my visibility (Hidden), I am using the following expression:
=iif(CDbl(ReportItems!tbOEM1.Value) >= 20 Or CDbl(ReportItems!tbOEM2.Value) >= 20 Or CDbl(ReportItems!tbOEM3.Value) >= 20 Or Parameters!OEM20.Value.Equals(False)
, False
, True
)
Which I think should mean, if any of the 3 tbOEM fields are >= 20, then display the row. But if the user has selected False for the "OEM20" parameter (Boolean), display all the rows regardless of the values.
However, when I run the report and choose True for the OEM20 parameter, No rows get displayed, even though I know that there are rows that have OEM values over 20.
To investigate, I added a background color expression to each of the tbOEM reportitems. Here is the background color expression for tbOEM1:
=iif(CDbl(ReportItems!tbOEM1.Value) >= 20
, "Red"
, "White"
)
When I run the report with False for the OEM20 parameter, I see all rows returned, and no fields are colored Red, even the ones that should be because they are tbOEM fields with a value >=20.
So I wonder if this is an order of execution issue where the value of the ReportItem is not yet known when setting visibility and background color? Is this known and documented anywhere? I googled and couldn't find anything.
Or am I doing something else wrong that is fixable?
I already know that a workaround is to use the datafield calculations that populate the tbOEM fields in the expressions, rather than the ReportItems collection. So you needn't bother to tell me about this option.
Here's some things to try. Putting this as an answer as it will be too big for a comment.
I'm still thinking something weird is happening with type comparison/conversion.
Maybe the tbOEM textboxes are strings with non-numeric characters (even just a space) so the CDbl conversion is failing, and thus failing the CDbl(ReportItems!tbOEM1.Value) >= 20 test even though it looks like it is above 20 when displayed as a string. Given your background colour expression is also failing, this seems to be the case. Let's use the Val expression for the comparison instead:
Val(ReportItems!tbOEM1.Value) >= 20
Val doesn't give errors when converting to a numeric value, it just does the best it can and returns whatever number it finds. Convert the field into the numeric value for display purposes as well as for the background colour expression so we see what the expression sees, not just the displayed text. On your tbOEM1 textbox use these expressions for the following properties:
Value
=Val(Fields!OEM1.Value)
Background.Color
=iif(Val(ReportItems!tbOEM1.Value) >= 20, "Red", "White")
If this still fails (for example, the textbox no longer displays a value) then let's trim it first to get rid of any spaces: =Val(Trim(Fields!OEM1.Value))
If the OEM1 field is a decimal value use 20.0 rather than 20 so it is comparing to a Double rather than an Integer in case something funky is happening with the implicit type conversion in the comparison.
Okay, now hopefully the textboxes are displaying the correct number and the background is being coloured correctly. Now we just need to fix the Visibility.Hidden expression for the row. I wouldn't use Value.Equals here as the parameter is already a boolean so we can just use it directly:
=iif(Val(ReportItems!tbOEM1.Value) >= 20 Or Val(ReportItems!tbOEM2.Value) >= 20 Or Val(ReportItems!tbOEM3.Value) >= 20 Or Not Parameters!OEM20.Value
, False
, True
)
This needs to be applied to the entire row by selecting the handle for the row on the left of the tablix, rather than applied to the textboxes directly.
Of course, add the Trim function if the experiment above required it.
Good luck! I hope this helps.

Switch function not returning correct value when referencing "nothing"

having a small issue here.
I have a Switch function in a report as shown below:
=Switch(
Fields!Duration.Value > 0, Round(Fields!Duration.Value / 60),
Fields!LastTime.Value = nothing, "Still Occupied",
Fields!LastTime.Value = Fields!FirstTime.Value, "Passing By"
)
This is for a column that is showing the total "Fields!Duration.Value" in minutes (rounded up), and it is working other than the second line:
If the Last Time value is the same as the First Time value, then it is assumed the object was just passing by and outputs "Passing By" and it does this correctly.
However, if the Last Time value is equal to nothing (it is defined in the column for "Last Time" that if it IsNothing, it is 'nothing', and it should output in this report with "Still Occupied" - which it's not doing. The cell is left blank, as if I have it written as Fields!LastTime.Value = nothing, nothing,
Why is this line of code not working?
Fields!LastTime.Value = nothing, "Still Occupied",
Thank you
You cannot test for Nothing using the = operator. There are two ways for which Nothing can be tested; using the IsNothing inspection function like this IsNothing(Fields!LastTime.Value) = True, or by using the Is operator like this Fields!LastTime.Value Is Nothing.
If these tests do not produce the expected result you may be dealing with a field that is set to something other than NULL, like empty '' or an arbitrary value. You can open the Query Designer on your Dataset properties to run your query and check the results.
You could also be looking at a mismapping with your dataset. Use the Refresh Fields button on your Dataset properties to verify your Field Mappings and then double-check that the name being used in your expression matches.
I found that using an IIF statement instead of a Switch statement worked for me, at least for this specific case:
=IIF(Fields!Duration.Value > 0, Round(Fields!Duration.Value / 60),
IIF(Fields!LastTime.Value = Fields!FirstTime.Value, "Passing by", "Still Occupied"))
Going to try to explain it for future people that might not understand (like me when I eventually forget it - I am very new to this sort of stuff) -
Rather than using the Switch statement I had in place to see if Fields!LastTime.Value is a number, equal to Fields!FirstTime.Value, or nothing, it now just asks if it is a number or if it is equal to Fields!FirstTime.Value, and if neither of those are true, it marks it as "Still Occupied" thus removing the need to reference nothing entirely. Like I said, this is pretty case specific, but you never know.
Thank you for the help #JamieSee and #SuperSimmer 44. Cheers!
Could be that nothing should be surrounded by " "

SSRS Count or Sum expression

I cannot work out why these Total expressions don't work...
I am trying to add any cells that have a date later than today, with any cells that have "Not Reqd", and then divide that by the number of rows, to get a percentage.
All I'm getting is #Error.
These are the expressions I've tried:
=SUM(IIf(Fields!Jetter_Trng.Value >Today OR
Fields!Jetter_Trng.Value = "Not Reqd",1,0)))/(Count(Fields!Jetter_Trng.Value)
and
=Count(IIf(Fields!Jetter_Trng.Value >Today OR
Fields!Jetter_Trng.Value = "Not Reqd",1,Nothing)))/(Count(Fields!Jetter_Trng.Value)
The "Not Reqd" string has come from an expression that changes a date (01/01/1950) to "Not Reqd". Maybe this is messing things up:
=iif(Fields!Jetter_Trng.Value = "01/01/1950", "Not Reqd", Fields!Jetter_Trng.Value)
The current working expression (not looking for "Not Reqd") is:
=COUNT(IIF(Fields!Jetter_Trng.Value>Today,1,Nothing)))/(Count(Fields!Name.Value))
I'm a bit lost...
A couple of notes on your expression as it stands at present
Jetter_Trng appears to be a string representing either a date or “Not Reqd”. You can’t compare strings to dates without casting them to a date type first using CDATE()
The number of braces (( and )) do not match
The root of your problem though is that you are using Jetter_Trng to return either a Date, or the value “Not Reqd”.
When SSRS attempts to evaluate an expression it does it all at the same time. It doesn’t follow a path to find the answer, and ignore other paths. Therefore, when you are attempting to compare
Fields!Jetter_Trng.Value >Today
This is comparing a string to a date, and throwing the error, as this mean nothing
"Not Reqd" > Today
You won’t be able to do all that you want to using only one Field of type string.
Your options are to
Use two fields – the date and a flag indicating not required, or
Use one field – but have an “invalid date” (01/01/2100 perhaps) that you could then treat as the “Not Reqd” value, and check if the current date is less than that (which it always will be)
Using the second option here you could then use the following expression to create the desired calculation
=sum(iif(CDate(Fields!Jetter_Trng.Value) > Today, 1, 0)) /
Count(Fields!Jetter_Trng.Value)
Which would evaluate this dataset as follows

SSRS and null datetime

I always thought that when a stored procedure brought back a null datetime that an SSRS report would show mindate in that cell. The thing is, in my experience this is not always true. I can't figure out why. Sometimes a report will show blank and sometimes mindate for a null datetime. Why is that?
Is there rules or documentation (that makes sense) that explains how this works? It's hard to be consistent when the tools you are using are not consistent. I can make two reports that are set up exactly the same way. One will show mindate and one will show blank for null datetimes. I don't get it.
EDIT:
First of all, yes the mindate thing has happened to many.
https://www.google.com/search?num=50&q=ssrs+null+date+show+blank&oq=ssrs+null+date+show+blank&gs_l=serp.3...8759.9774.0.9941.10.10.0.0.0.0.152.888.8j2.10.0....0...1c.1.25.serp..8.2.166.kl2WBVx4Ijw
Almost every result has someone talking about the mindate when they want a blank. Many of the results are from Stack Overflow so before you start telling me it never happens, realize you are flat wrong. You may have never seen it. I have never seen a severed finger in my food in all my years of eating and thousands of meals. Doesn't mean it hasn't happened to someone.....
Example of one that is showing min date:
In the report the expression for the text box is:
=Fields!SecondaryInjuryRecordDate.Value
The number formatting was set to Date->01/31/2000 in the placeholder properties window.
Pretty straightforward, nothing weird going on there. RIGHT?
In the proc, the code for that column is:
CASE WHEN ISNULL(l.SecondaryInjury, 0) = 0 THEN '' ELSE l.SecondaryInjuryDXDate END AS SecondaryInjuryRecordDate
That resulted in mindate being shown whenever SecondaryInjuryDXDate was null. I had to switch to this:
CASE WHEN ISNULL(l.SecondaryInjury, 0) = 0 THEN '' ELSE ISNULL(l.SecondaryInjuryDXDate, '') END AS SecondaryInjuryRecordDate
...to get blanks when the date was null.
SecondaryInjuryDXDate is a DATETIME and
SecondaryInjury is a bit.
Within SSRS, by default a NULL DateTime value will be represented as an empty string instead.
If data formatting is applied to the value, a MIN DateTime value will be used in place of the null value e.g.: converting the DateTime to a ShortDate as described:
The number formatting was set to Date->01/31/2000 in the placeholder properties window. Pretty straightforward, nothing weird going on there. RIGHT?
To avoid this, the column value must be wrapped in an expression to conditionally apply the required formatting:
=IIf(IsNothing(Fields!DateTimeField.Value), "", FormatDateTime(Fields!DateTimeField.Value, DateFormat.ShortDate))
Use something like this in textbox expression:
=IIf(IsNothing(Fields!DateTime.Value), "", Fields!DateTime.Value)
It looks like there is no documentation to be found about this. The next best thing is to have this Q&A document things based on our collective experience.
Supposing the question: "What does SSRS do when displaying a DATETIME with a NULL value?"...
...the answer is it will display an empty string instead. There is no reproducible scenario where a NULL value would be displayed as anything else, unless you do some work to that end yourself, for example:
If the query COALESCEs the NULL to something else, e.g. the string "NULL" or a MIN DATETIME;
If you have an expression for the textbox value, e.g. IIF(Fields!MyDateTime.Value Is Nothing, "01-01-1900", Fields!MyDateTime.Value)
Every field returned in a SQL query gets a datatype assigned. Generally, you want to keep dates returned as dates from SQL, not as strings. (Don't format the date to a string in SQL. Do that as close to the presentation layer as possible.)
So instead of this in your query:
CASE WHEN ISNULL(l.SecondaryInjury, 0) = 0 THEN '' ELSE l.SecondaryInjuryDXDate END AS SecondaryInjuryRecordDate
I would try to use:
CASE WHEN ISNULL(l.SecondaryInjury, 0) = 0 THEN CAST( NULL AS DateTime ) ELSE l.SecondaryInjuryDXDate END AS SecondaryInjuryRecordDate
See SQL cast datetime for an explanation of why you are getting 0 cast to a date.
I did find when I format an entire column such as FormatDateTime(field, DateFormat.ShortDate) - SSRS will format that blank field to 01/01/0001. Just an FYI.

SSRS expression editor does not recognize embedded code function

I have an SSRS report with information about invoices my company has issued with things like amount, date, payment, amount due, etc. I'm using SSRS 2008 (not R2) in Visual Studio 2008 environment. My issue has to do with formatting the report using the Expression editor. Currently, an invoice will be formatted as silver if the invoice has an Amount Due (a column) over 0.01 (outstanding invoice). We also issue credits (negative amounts) and these are almost always the negative amount of a previous invoice.
So, an invoice that has a credit issued to it will still show as silver because it's amount due > 0.01. But if there is a credit issued to this invoice, it's not actually outstanding and should be white. For example, if an invoice is $100.00, and there is a credit after for ($100.00), the original invoice's background color should be switched to white.
Here's where the code explanation comes in. I thought this was possible with custom VB code in the report, but it seems like the Expression editor in SSRS will not recognize my function as it says "Unrecognized identifier". I googled this a bit, and most of the topics I came across said that it will show that but actually work anyway. Well, I'm pretty sure it's not working at all, because I put this in as my expression and got all white cells for a certain column:
=IIF(Fields!Amount_Due.Value > 0.01,
IIF(Code.HasCredit(Fields!Amount_Due.Value) = True, "Blue", "Silver"), "Red")
The HasCredit function is below.
Function HasCredit(ByVal currentAmt as Double) As Boolean
Dim i as Integer
Dim amt as Double
Dim amts as System.Collections.ArrayList = New System.Collections.ArrayList()
Dim negativeAmt as Double
Dim retValue as Boolean = "False"
i = 0
For i = 1 to Report.Parameters!Test.Count()
amt = Report.Parameters!Test.Value(i)
amts.Add(amt)
Next
negativeAmt = currentAmt * -1
If amts.Contains(negativeAmt) Then
retValue = "True"
End If
Return retValue
End Function
When these two pieces are run, I get white background for all cells of this column. I read something on the net saying that only Shared functions would work, but I found multiple other examples showing functions that were not shared that worked. When I make it shared, it gives me: BC30369 Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class. due to the Report.Parameters!Test.Count() line. I got the idea for using Report.Parameters from http://social.msdn.microsoft.com/Forums/en-US/sqlreportingservices/thread/a7d59224-0ee5-491e-883b-2e5fcb3edeab.
So to reiterate, what I'm basically trying to do is get the values of each cell in this column into a collection and, for any two amounts where one amount has a negative equivalent, give it a white background instead of silver.
In SSRS 2008 R2, even if you reference a valid custom code method, the expression editor may still warn that the identifier is invalid. This does not always mean that it's invalid. My function worked even though that warning was thrown.
After a bit more researching I figured out how to solve this. I basically had to add a textbox with the =Join() function so that all the values in a column were put in this textbox; then reference the textbox in custom code and use a boolean value in the expression editor. Detailed instructions below.
1) Add a multi-valued parameter to your report (Right click Parameters, Add Parameter). Name it, select Allow Multiple Values, select Hidden for parameter visibility. For Available Values tab, select Get values from a query. Point to your dataset, and set the Value field to the column you want the parameter to check. For me that was my Amount Due column. Label field is irrelevant and can be left blank. In the Default Values tab, do the same, make sure the value field is set to the same column as before. Under Advanced, select Never refresh.
2) Create a new textbox on your report. Might want to name it, ex txtColumnValues. Edit the expression and put this in: =Join(Parameters!YourParameter.Value, ",") This will get all of the field values from the column you specified in your parameter, each separated by a comma.
3) Edit your report's custom code and make a VB function (as Boolean) to check the textbox. For example here is my code.
Public Function HasCredit(Amt as Double, ri as ReportItems) as Boolean
Dim retValue as Boolean = False
If Amt > 0.00 AndAlso ri!txtAmounts.Value.Contains(Amt*-1) Then
retValue = True
End If
Return retValue
End Function
4) Finally go to your expression editor for the field you want to change. In my example I wanted to change the background color if the current field had a negative equivalent in one of the other fields (my textbox), so my code looked like this:
=IIF(Fields!Balance.Value > 0.01
AND Code.HasCredit(Fields!Balance.Value, ReportItems) = False, "Silver", "White")
I had to take separate pieces of info from 3 or 4 pages, put them together, and hope they worked... after about a week they did... I guess it's all about persistence. If you need any further help with this just let me know.