SSRS - How to make IIF statement ignore invalid values - sql

I am creating a table in SSRS with Business Intelligence 2008. I have a date, as a string, as one of the values used in the table. This value may have a string representing a date, OR it could also be blank. If it has a value, I want the value formatted in a different way. Right now, I have this expression for the cell in which it is displayed:
=IIf(Fields!MyDate.Value = Nothing, "", Format(CDate(Fields!MyDate.Value), "dd-MM-yyyy"))
This works perfectly if the field has a value. However, when the field is blank, the cell is populated with #Error. This would make sense if I just had the Format function, but it seems like the IIf should prevent it from trying to run that with a blank value. I tested it with this expression:
=IIf(Fields!MyDate.Value = Nothing, "No value", "Value")
...and sure enough the blank values entered the correct part of the statement and printed "No Value". I don't understand why the second part of the expression, which isn't used, would cause an error. Is there a way to rewrite this that will not cause an error? Thanks
EDIT: As I mentioned in the comments, I also tried a switch statement like this:
=Switch(Fields!MyDate.Value = Nothing, "", Fields!MyDate.Value <> Nothing, Format(CDate(Fields.MyDate.Value), "dd-MM-yyyy"))
However, this returned #Error for blank values as well.
EDIT Regarding Possible Duplicate: PLEASE do not mark this as a duplicate to the question asking whether IIf short-circuits. I looked there, it asks a different question and does not give an answer that works for what I need.

The problem is that Iif does not short-circuit. One ugly workaround is to use a nested Iif:
=IIf(Fields!MyDate.Value = Nothing, "", _
Format(CDate(Iif(Fields!MyDate.Value = Nothing, Today(),Fields!MyDate.Value)), "dd-MM-yyyy"))
Which is ugly, repetetive, and error-prone.
Another option is to create a custom function that does short-circuit:
Public Function FormatOrBlank (ByVal theDate As DateTime, ByVal format As String)
If String.IsNullOrWhiteSpace(theDate)
Return ""
Else
Return Format(CDate(theDate)), format)
End If
End Function

Related

index was outside bounds of array in SSRS when parameter come as blank

I am working on SSRS report where user!userid variable coming with 3 pipe delimited values
E.g :
ReportUser |500|100
I split the values using below expression
=(Split(Parameters!QueryString.Value, "|")).GetValue(0)
=(Split(Parameters!QueryString.Value, "|")).GetValue(1)
=(Split(Parameters!QueryString.Value, "|")).GetValue(2)
When the parameter is coming with values above expression works fine. But, when any parameter coming as blank, I am getting below below error during report execution.
index was outside bounds of array for the parameter.
I tried below workarounds with iif expression
=iif((Split(Parameters!QueryString.Value, "|")).GetValue(0)=NOTHING,0,
(Split(Parameters!QueryString.Value, "|")).GetValue(0))
=iif((Split(Parameters!QueryString.Value, "|")).GetValue(0)="",0,
(Split(Parameters!QueryString.Value, "|")).GetValue(0))
Still I am getting the same error. Could someone help how to handle the blank values with this expression?
I had initially though that this would work
This code fails
=SWITCH
(
Split(Parameters!QueryString.Value, "|").Length <3, "",
True, Split(Parameters!QueryString.Value, "|").GetValue(1)
)
As Switch stops evaluating at the first True result but for some reason I still got an Error. I'm not sure why this happens but I got round it by writing a function to do the work.
This does work
I added this code to the Reports Code property (it can probably be made better but I've not done any VB.Net for years)
Public Function GetSplitValue(inputString as String, delim as string, index as Integer) as String
Dim arr() AS String = Split(inputString, delim)
Dim result AS string
TRY
result = arr(index)
CATCH
result = ""
END TRY
RETURN result
End Function
You can then call this in your expression using something like this in your text boxes or whatever you are populating.
=Code.GetSplitValue(Parameters!QueryString.Value,"|",0)
=Code.GetSplitValue(Parameters!QueryString.Value,"|",1)
=Code.GetSplitValue(Parameters!QueryString.Value,"|",2)
If you want something other than an empty string, just edit the code in the CATCH block.

VB.net application using reader HasRows

I am running an SQL Query with data readers in vb.net
reader3 = myCommand3.ExecuteReader
reader3.Read()
If reader3.HasRows Then
FromToDates = reader3.GetString(3)
End If
There are no rows being returned in this particular query, however even though the if reader3.HasRows is being used its still showing an error saying:
Additional information: Data is Null. This method or property cannot be called on Null values.
this is when trying to set the FromToDates variable but there are no rows being returned so it should not even reach this part
I doubt that there are no rows, i assume that there is at least one row where the value is NULL. You could check it with the IsDBNull-method:
If reader3.HasRows AndAlso Not reader3.IsDbNull(3) Then
FromToDates = reader3.GetString(3)
End If
However, the variable name suggests that it's a date, but you are storing it as string. Use the correct type which is date or datetime. If it's actually a datetime use:
Dim FromToDates As Date
If reader3.HasRows AndAlso Not reader3.IsDbNull(3) Then
FromToDates = reader3.GetDateTime(3)
End If
if you are using Reader.read() then i don't think so you need reader,hasrow(). you can do somthing like this
reader3 = myCommand3.ExecuteReader
If reader3.Read()Then
FromToDates = reader3.GetString(3)
End If
and related to your error its look like you are getting NULL value from database and in vb you can not read NULL, i will suggest to use ISNULL(Column_NAME,'') function in your SQL Script.
It seems that even though the row is empty (all DBNull, perhaps), there IS a row object returning from the query. There are several different solutions presented in this thread that all take differing approaches to catching the empty row before it errors!
http://www.vbforums.com/showthread.php?555183-datareader-and-empty-records

Strange behaviour of the If() statement

today I stumbled upon a strange behaviour of the VB.net If() statement. Maybe you can explain why it is working like it does, or maybe you can confirm that it is a bug.
So, I have a SQL database with a table "TestTable" with an int column "NullableColumn" that can contain NULL. I'd like to read out the content of this column.
So I declare a variable of type Nullable(Of Integer) for that matter, open a SqlClient.SqlDataReader for "SELECT NullableColumn FROM TestTable" and use the following code to get the content of this column:
Dim content as Nullable(Of Integer)
...
Using reader as SqlClient.SqlDataReader = ...
content = If(reader.IsDBNull(reader.GetOrdinal("NullableColumn")), Nothing, reader.GetInt32(reader.GetOrdinal("NullableColumn")))
End Using
But after that my variable content has the value 0, not Nothing as I would have expected.
When debugging everything looks alright, so
reader.GetOrdinal("NullableColumn") delivers the correct ordinal position of this column (which is 0)
reader.IsDBNull(0) and reader.IsDBNull(reader.GetOrdinal("NullableColumn")) deliver True, since the content of this column indeed is NULL
If(1=2, Nothing, "Not Nothing") delivers the String "Not Nothing"
If(1=1, Nothing, "Not Nothing") delivers Nothing
reader.GetInt32(reader.GetOrdinal("NullableColumn")) throws an error, since NULL can't be converted to Integer
So, why does my variable has the value 0?
In VB Nothing is not the same as null. The If operator must determine the type of its result based on the arguments passed to it. Nothing, of course, has no type so the only type that the If operator can return in your code is Int32. If the IsDBNull method returns true, then the If operator returns Nothing cast as Int32. In VB, Nothing returns the default value for a type. For an Int32, the default value is 0.
From MSDN on the Nothing keyword:
Nothing represents the default value of a data type. The default value depends
on whether the variable is of a value type or of a reference type.
For non-nullable value types, Nothing in Visual Basic differs from null in C#.
In Visual Basic, if you set a variable of a non-nullable value type to Nothing,
the variable is set to the default value for its declared type. In C#, if you
assign a variable of a non-nullable value type to null, a compile-time error
occurs.
I think just a regular If would work best:
If Not reader.IsDBNull(reader.GetOrdinal("NullableColumn")) Then
content = reader.GetInt32(reader.GetOrdinal("NullableColumn"))
End If
Or to keep it shorter
If Not reader.IsDBNull(reader.GetOrdinal("NullableColumn")) Then content = reader.GetInt32(reader.GetOrdinal("NullableColumn"))
But after that my variable content has the value 0, not Nothing as I would have expected.
How do you check the content value?
First of all, you should start with content.HasValue property. It should be False for your case of Nothing and True when correct value was fetched from database.
You should also get InvalidOperationException while accessing content.Value when it hasn't got value.
Chris has given the explanation but I dislike the style of assignment he’s chosen because it splits assignment from variable declaration.
By contrast, I recommend initialising variables upon declaration. In this case it’s admittedly slightly convoluted since you need cast either operator of If to the correct type first.
Dim content = If(reader.IsDBNull(reader.GetOrdinal("NullableColumn")),
DirectCast(Nothing, Integer?),
reader.GetInt32(reader.GetOrdinal("NullableColumn")))
Actually you can also use the slightly shorter New Integer?() instead of the DirectCast.
Of course now content is declared inside the Using block – this might not be what you want but you should try to make the declaration as local as possible.
Furthermore, this code is complex and will probably be reused. I suggest creating a separate (extension) method to convert database NULL values to nullables:
<Extension> _
Public Shared Function GetNullable(Of T)(SqlClient.SqlDataReader this, String fieldName) As T?
Dim i = this.GetOrdinal(fieldName)
Return If(this.IsDBNull(i), New T?(), this.GetFieldValue(Of T)(i))
End Function
Now you can use it as follows:
Dim content = reader.GetNullable(Of Integer)("NullableColumn")

Razor VB - Pass a Null value if a Request variable is empty

I've been trying so hard to find a solution for this, but no luck. I'm fairly new to VB and SQL, but this shouldn't be too hard. I've inherited a lot of code and there's not too much room to change db attribute types or anything.
I'm trying to run an UPDATE query using parameters in Razor, like so:
Dim updateCommand = "UPDATE [tblJobRating] SET [ProjectManagement] = #0, [ProjComments] = #1, [Schedule] = #2, [SchedComments] = #3 WHERE [JobRatingID] = #4"
All of the columns in question need INT values, but I have one exception where I need to pass it a null value (passing another number or zero won't do). Essentially a "N/A" value for the user.
I assign the variables from Post requests, like so:
Dim projMgmt = Request.Form('projMgmt')
' ...
Dim sched = Request.Form('sched')
I have the "N/A" value posting no value right now (or it can be a string and I can check for IsNumber if need be, I guess). But when I call the query execution, it enters the value as a 0.
db.Execute(updateCommand, projMgmt, projComments, sched, schedComments, ratingId)
It needs to be a NULL value for the backend to work properly. I've tried type checking and passing Nothing, System.Data.SqlTypes.SqlInt32.Null, etc., but it either gives conversion errors or sets to 0. How can I pass it properly?
Edit: I left out the first param in the db.Execute method, passing in the updateCommand. Edited for clarity.
The problem is in your vb variable definition. I assume you have an integer, it needs to be a nullable(of integer) all the way through to the SQL. This can also be written as integer?.

VS2008 reporting IFF is failing on a simple condition

I have a simple report in VS2008. I have a table which is like this:
I get the results as this:
I have already wasted 2 hours sitting in front of this issue. Moreover, my colleague didn't see any mistake in this either. I am 100% certain I have no formatting on the table. The results in the field value come as a string.
What wrong am I doing in the last column's code?
P.S. I have also tried
=IIF(IsNumeric(Fields!value.Value), Fields!value.Value, Fields!value.Value)
but then the data in the third column is showed as in the first one.
It seems that for some weird reason IIF is trying to parse both True and False parts and failing CDbl() on a string, but I cannot believe this can be possible, because I haven't seen a programming language doing something like this before.
After the comments on my post, I came up with a solution by writing these two functions. These two were both used to display data and overcome the stupidity of uneditable total field.
Public Function cdblf(ByVal s As Object) As Object
If (IsNumeric(s)) Then
Return CDbl(s)
Else : Return Nothing
End If
End Function
Public Function cdbls(ByVal n As Object, ByVal s As Object, ByVal b As Boolean) As Object
If (IsNumeric(n)) Then
Return CDbl(n)
Else :
If(Not IsNothing(s)) Then
If(b) Then
Return CStr(Left(CStr(s), Len(CStr(s)) - 1))
Else : Return Nothing
End If
Else : Return Nothing
End If
End If
End Function
The usage of these functions combined should be like this:
=Code.cdbls(
Sum(Code.cdblf(Fields!value.Value)),
Fields!value.Value,
InScope("matrix1_row_name") and InScope("matrix1_column_name"))
This both solved the fact that I didn't want to sum string values and also there was no need to use IIF anymore.