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.
Related
I created a MS Access database for tracking some items at work. Users enter data which is then aggregated in queries (using count or sum) to calculate the actual value for each area, joined using UNION, then compared to goals for that area. I attempted to enter an IIF statement to conditionally calculate the percentage of [Act]/[Goal], leaving it zero if [Act] is blank or 1 if [Act] is greater than [Goal] so there is nothing over 100%. The issue is that it works most of the time, but other times fails with no obvious logic error or reason why that I can figure out.
Sometimes it can't tell that [Act] > [Goal] even though looking at it, it's obvious. The numbers are all integers, nothing crazy or formatting differences. The formula in [Met] is what I hope to achieve. I added the [TEST] field to trace back where it might not be working, which shows Access just isn't always returning the correct answer to [Act] > [Goal].
My Query:
What comes out (just the broken part):
As you can see, it works correctly for most rows, but then thinks 149 is less than 52, and 128 is less than 3. Because of this, it generates [Met] values over 100%.
Has anyone had this happen before or have any suggestions? I have tried using refresh, clicking in the cell to hit enter, everything I can think of.
I think that although your columns are Ints, they are being converted to strings in the variables (or at least one of the variables) Goal and Met.
If you look at the data, you'll see that if you compare them the results of Test are correct for a string comparison.
E.g. "3" > "128" (Because the first character has a higher char value).
In your query, try surrounding the variables with Val() when you are comparing them, as follows:
IIf(IsNull([Act]),0,IIf(Val([Act])>Val([Goal]),1,Round([Act]/[Goal],2)))
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
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.
I have the details of my report being summed up in a summary expression, all works fine. The fields are decimal values of hours worked. Thus, the summary value is also a decimal value. I'd like to access the summary value and convert it to hours / minutes. I've labeled the express as "WorkTimeSum", but can't seem to get a handle to it, however. Fields! obviously won't work since it is a summary expression. I was thinking ReportItems! should work, but to no avail. How can I use this expression field (in a summary row) in an expression in the same summary row?
If I've understood correctly, you're asking how to reference the textbox containing the total work hours value so that you can convert it to hours and minutes using an expression in a different textbox?
You can use either ReportItems! e.g.
=ReportItems!Textbox20.Value)
or ReportItems("") e.g.
=ReportItems("Textbox20").Value
to reference the value of another textbox. Be careful with the names as they are case sensitive.
You can use aggregate functions in any expression. For example, in any header rows you can use the following expression to determine the total hours value:
=Floor(Sum(Fields!hours.Value))
Sum(Fields!hours.Value) is just the total hours in whatever context, e.g. the group total if it's a group header row; you can use this expression as an input in any other expression you require.
It sounds like your issue wasn't the conversion itself, so hopefully this points you in the right direction. If you need further information please specify.
Lets say I have two text boxes on a form. the first returns a count value from a SQL statement, or a domain aggregate expression, etc. the second does the same with additional parameters.
Now i want to have another text box (#3) that divides one by the other for a very simple percentage. like this for a controlsource:
=[textbox2]/[textbox1]
this works great unless the original counted value returned is a zero. If the first returned value is a zero, then the second is going to be a zero too, and ideally 0 / 0 should come out to zero, but I get a #Num! error string in the text box.
I realize this is yet another weird request but this is for a dashboard form that has about 50 of these, and they work great, unless I hit a zero.
So is there any way I can set text box properties that i may be unaware of, for this to work without having to write numerous If statements in the code?
Thanks!
I cannot see how you can avoid an if statement when divide by zero is a possibility
=IIf(TextBox1<>0, TextBox2/TextBox1,"N/A")
Mathematically, the division by 0 is undetermined, but for your purposes, you can calculate it with:
=IIf([textbox1]<>0;[textbox2]/[textbox1];IIf([textbox2]=0;0;"N/A"))
This is, when textbox1 equals 0, you check whether or not textbox2 equals 0. If this is the case, then return 0, which is what you want.