End of Amnesia (Avoiding Divide By Zero Errors)
People often ask how to avoid divide by zero problems in their Reporting Services reports. Let's say you have a textbox that calculates profit margin via the expression:
=Fields!Price.Value / Fields!Cost.Value
This works fine unless a value in the Cost field is zero (and is not an integer or double), in which case you will get '#error' displayed in your report. This is because a divide by zero with a decimal field will throw an exception. This exception is caught by the report processing engine and #error is displayed. If you would rather have a string like "N/A" instead of #error, you might think about creating a Reporting Services expression using the IIf function:
=IIf(Fields!Cost.Value = 0, "N/A", Fields!Price.Value / Fields!Cost.Value)
But when you preview the report, you still see #error in your report. What gives?
If you take a look at the IIf function description in the Visual Basic documentation, you will see the following:
As part of preparing the argument list for the call to IIf, the Visual Basic compiler calls every function in every expression. This means that you cannot rely on a particular function not being called if the other argument is selected by Expression.
This means that even through the value for cost is zero, the error will still be generated. So how do you work around this? You have to force the expression evaluation to avoid the division with a nested IIf:
=IIf(Fields!Cost.Value = 0, "N/A", Fields!Price.Value / IIf(Fields!Cost.Value = 0, 1, Fields!Cost.Value))
The nested IIf is evaluated first so that the divide by zero can be avoided but is not used by the outer expression if it is zero.
As an interesting side note, the Arithemtic Operators topic in the Visual Basic documentation seems to say that a DivideByZeroException is thrown for dividing by anything but the Double data type. I have not found this to be the case. Try this simple application in VB:
Dim a, b As Integer
a = 1
b = 0
MsgBox (a / b)
You will get "Infinity", despite what the documentation says. Anyway, the use of the expression above in your report will ensure that you will get the desired results, no matter what data type you are using.
Comments
- Anonymous
September 26, 2006
Impossible, infinity can not be stored in an integer. The reason is that Dim a, b as Integer does not do what you expect. It declares a as Variant and b as Integer :) - Anonymous
September 26, 2006
Actually, I now realize why I get infinity instead of an exception when dividing integers. There is an implicit cast to a double for the result of integer division. - Anonymous
September 28, 2006
Actually, "Dim a, b as Integer" does not declare a as Variant. If you do this:
Dim a, b As Integer
MsgBox(a.GetType().FullName)
You will get System.Int32.
The reason for the Infinity is what I stated in the next comment, there is an implicit cast to a double for integer division. - Anonymous
September 29, 2006
I end up implementing a little VB function in the Code tab of every report called SafeDivision. It would be great if you folks could just add that to the SSRS object model as a standard function. - Anonymous
October 11, 2006
Perfect. This confirms my suspicions and keeps me from fumbling for the answer. Blogs + Search = Love. - Anonymous
October 31, 2006
The comment has been removed - Anonymous
March 05, 2007
Thanks again. I wish I'd done a better search an hour ago! - Anonymous
June 14, 2007
Thanks a lot!!! This worked like a charm. I was getting really frustrated because it didn't make sense what it was doing. - Anonymous
September 05, 2007
A True Tenary operator is come with Orcas. View the article about the old IIF and New IF in VB 2008http://www.itgalary.com/forum_posts.asp?TID=586 - Anonymous
September 28, 2007
The nested IIF worked very well, however this construct is very non-intuitive. I was going round and round on avoiding the #error. Seems like this should be the default behavior:=IIf(Fields!Cost.Value = 0, "N/A", Fields!Price.Value / Fields!Cost.Value)Otherwise, it's off to google ... - Anonymous
March 23, 2011
Glad this is still out here. Saved me a ton of time. Appreciate it! - Anonymous
April 15, 2011
Props... This posts resolved a lot of anger :)!!! - Anonymous
April 15, 2011
Props... This post resolved a lot of anger :)!!! - Anonymous
May 22, 2011
Thanks a lot!!! This worked like a charm. I was getting really frustrated because it didn't make sense what it was doing. http://www.oddarena.com - Anonymous
May 25, 2012
=IIf(Fields!Cost.Value = 0, "N/A", Fields!Price.Value / Fields!Cost.Value)Change to=IIf(Fields!Cost.Value = 0, 0,( Fields!Price.Value / Fields!Cost.Value)) - Anonymous
August 15, 2012
still does not work=IIf(Sum(Fields!HOURS.Value,"Group1") = 0.00, "N/A", FormatPercent(Sum(Fields!HOURS.Value, "Details")/Sum(Fields!HOURS.Value,"Group1"))) - Anonymous
January 15, 2013
furmangg: "I end up implementing a little VB function in the Code tab of every report called SafeDivision. It would be great if you folks could just add that to the SSRS object model as a standard function."+1!Something like this would do it: SafeDivision(<division expression>, <return string in case of div by zero>)That would make it flexible enough so that we can still take action in case of div by zero (or just display a "Div by zero" msg if that's what's required). - Anonymous
July 01, 2013
million thanks! been searching for hours!..thanks. - Anonymous
October 10, 2013
Much needed article to avoid confusion with "IIF" , Thanks !!!