I have a SSIS package that I am programming and my script component won't allow null column inputs. I have checked the box to keep nulls in the flat file source component. My program is running well until my script component where I get the error "The column has a null value" (super vague, I know). The column currently throwing the error is an "int" valued column and is used for aggregations in my script.
I could make the null values 0s or to say "NULL" but I'd prefer to just leave them blank.
I am using SQL Server BIDS 2008.
So because SSIS deals with the databases so much and doesn't want to spend a lot of time differentiating between DB NULL and C# NULL, they create boolean properties for each input column in the Buffer with the naming convention (columnname)_IsNull. You can read more about that on MSDN.
So you have to use those buffer columns to determine whether the value is null and then doing whatever you're trying to do with that column in the component.
So something like
if (!Row.MyColumn_IsNull) {
//do something }
else {
//do something else, or nothing, etc.
}
While Kyle's answer is very sufficient, I used a different method that is working just fine. I used the ternary for c#.
Value = Value_IsNull ? True Value : False Value;
Row.rowname = Row.rowname_IsNull ? 0 : Row.rowname;
This changed the value of my null integer columns to 0 if they were null coming into my script. Otherwise, it retained the value.
Is your error occurring in the C# code somewhere? It gets a little maddening at times when you have a database column with the datatype int, and it allows nulls. In C# land you have to use the int? as apposed to int when you need to accept nulls. Otherwise the approaches mentioned already are a good way to go.
Related
As the subject expresses, I'm trying to sum the values of a string field where spaces may exist. It must be done this way, unfortunately.
The database is very old. The original developer chose to make all fields Text fields; to get over the null value problems, a function was written in VB6 to replace any null value with a space. This cannot be changed.
Fast forward to now, I'm trying to create a report that sums the length field without changing spaces to nulls first, and it should be done entirely through the control source property of the report.
I've added some of what I've tried below, but every time the report is run, I receive:
Data Type Mismatch
...and I'm not sure how to get around it.
Ideally, I'd like to keep the users out of the database completely, and just add a combo box that lists the reports created in the database so they can be opened by name without having to run any additional update queries first.
=Sum(IIf([MY_LEN]<>" ",DCount("[MY_LEN]","MY_TABLE"),0))
=Sum(Nz(Iif(Trim([MY_LEN])='',Null,[MY_LEN]),0))
=DSum("[MY_LEN]","[MY_TABLE]","[MY_LEN]<>' '")
=Sum(Iif(Val([MY_LEN])>0,[MY_LEN],0))
=(SELECT Sum([MY_LEN]) AS MyLen FROM MY_TABLE WHERE (((MY_TABLE.[MY_LEN])<>' ')))
Is this possible?
Can't compare anything to Null. Can't say If x = Null Then because Null is undefined. So you can't test if undefined = undefined. Use If IsNull(x) Then in VBA and Is Null in query criteria. Don't really need IIf() for Sum() aggregate, other aggregates such as Count or Avg would.
To handle possible space, empty string, or Null for a text field holding numeric data.
=Sum(Val([MY_LEN] & ""))
I have a parameter of integer datatype which is hidden. When i run the report, report gives me an error
Parameter X is missing a value
However if i make the parameter visible it works. I tried providing default value of 0 but that does not suffice my requirement as i have sub-report(Drill-dowm) depended on this parameter. Please help. Thanks!
Make sure that you have not specified Available Values for the parameter. Available Values should be "None" for internal and hidden parameters.
First of all,
Check that parameter's - Available Values by going to report parameters properties.
It must not be specified any values. So we should set it as None
Second work around is,
Just add a blank space at Specify values - in Default values inside report parameters properties.
This will surely work. Hope it will save your time.
I had to do an "if exists" statement for this to go away. It worked for me because it makes it always return a value even if that value is not need by my query.
if exists (my select query)
my select query
else
select '2'
// '2' would never be used, but it made ssrs stop giving me
// the stupid error and execute the rest of the query
If you specify available values from query, then default values must be in list of available values. Default value in (Available) = true.
The problem occurs also, if you have a parameter that depends of another one without "default value" inside the Dataset Query and does not admit null value.
For example:
Parameter 1 have a default value: NameEmployee from the dataset "EmployeeSearch"
But the dataset "EmployeeSearch" have a filter or a parameter inside the query named #Month that indicate the number of the month. So if the value of #Month is null, SSRS will say "Parameter is missing a value".
Assuming you had the same issue as I had, trying to run the report on a web page using a ReportViewer component, I managed to fix that issue by adding a null parameter before rendering the report:
C# code:
var parameters = new List<ReportParameter>();
parameters.Add(new ReportParameter("ParameterName", (string)null));
ReportViewer1.ServerReport.SetParameters(parameters);
Hope that will help
Just need to add 1 default value to get around this error (even though that default value will never be used).
-Under "Report Parameter Properties" for that specific parameter, go to the Default Values page.
-Toggle "Specify values"
-Add a value (I added: "just_a_filler_to_get_around_hidden_value_error" so when I look back at it later I remember why I did such a thing)
-click OK
I want to add to dmbreth's CORRECT answer.
I was missing the concept that the value of the parameter still needed to be tied to something. Originally, I was tying the output of a dataset by using the Available values portion of the parameter properties, but according to dmbreth's answer, that could not be the case. Finally I moved my output dependence settings from the Available Values section to the Default Values section and that did the trick.
So, in summary, in the parameter properties dialogue:
General Page - Allow multiple values checked(this option is specific to my application), parameter visibility set to internal
Available Values Page - None
Default Values Page - Get values from query, [appropriate dataset, value here]
Advanced Page - No significance here
Hopefully, that is clear enough to benefit someone else with the same problem...
I had a similar issue where the default value as set by SSRS is (Null), I didn't need the parameter for my report however; I found it useful for testing to filter down the list so I kept it, I guess I could have deleted it in SSRS on the dataset config. but I changed it to =System.DBNull.Value (I guess this could be any expression) instead and that worked for me, so then I can still pass in a value if need be and also set Available values (had to make sure a NULL value was added to my dataset) if I then decide to unhide at a later date.
There is one other potential here. I have had a situation where the report designer works but the server report object does not. The solution is to delete the server object and then re-save it from the designer.
Is it possible to write extension methods for expressions behind RDLC fields?
For example, let's say that I have a DateTime field in my datasource that may either have a valid value or may be null. I drag and drop a TextBox onto my RDLC and format its value using the ToShortDateString() method. This works fine for populated DateTime value, but this will also obviously throw an exception at runtime if I try to do a .ToShortDateString() on a NULL field.
I was wondering if I could write an extension method that I could use in my RDLC expressions so that when I'm dealing with ?DateTime values, I could call a method like .ConvertFromNullToEmptyString().
Of course there are other ways to work around this issue, but I was wondering if extension methods for use in RDLC expressions would be a possible approach to my business problem.
Thanks folks!
Yes, this is possible. You can either embed code directly in the report or include a custom assembly.
It is possible to use extension methods, but not AS extension methods on an instance of an object. You would have to call them as a static method call on the type of which they are a member. So instead of myDictionary.Values.Sum() -- calling the Sum method on the Values property of a dictionary instance -- you could use System.Linq.Enumerable.Sum(myDictionary.Values) -- passing the instance into the static Sum method of the Enumerable type (in this example, the report must reference the System.Core assembly). So yes, you can use methods that are also extensions, but (it appears anyway) not as extensions on a particular instance.
While I agree with Corina on the solution to the question, I believe a better solution can be reached without going the route she suggests, using built in expressions. In any case where you have a DateTime coming from SQL, you're correct, it can be null, however, you can easily test for this using an IIF statement (remember that the expressions are basically in VB) to check for null / nothing / empty and as long as it is something, run the desired operation, otherwise return blank. Just be careful, as the resulting type of the IIF will probably be string.
For example, let's say that I have a DateTime field in my datasource that may either have a valid value or may be null. I drag and drop a TextBox onto my RDLC and format its value using the ToShortDateString() method. This works fine for populated DateTime value, but this will also obviously throw an exception at runtime if I try to do a .ToShortDateString() on a NULL field.
There should be no need for a custom function in your case. Just use VB's If() ternary operator:
=If(Fields!MyDate.Value IsNot Nothing, Fields!MyDate.Value.ToShortDateString(), "N/A")
(Personally, I funnel my objects through AutoMapper and let it substitute null values with default values or objects, so that I don't have to deal with null values in the report at all).
It should be mentioned, that the If(condition, true_part, false_part) ternary operator should (with one I) be preferred over the IIf(condition, true_part, false_part) function (with two I's) in most cases.
The If() ternary operator will short-circuit evaluate only the part that corresponds to condition outcome (e.g. a condition that is True will only evaluate the true_part).
The IIf() function will always evaluate the condition and both parts, because it is just a function call and all parameters of the function will be evaluated before the call.
Item in the recordset rstImportData("Flat Size") is = Null
With that, given the following statement:
IIF(IsNull(rstImportData("Flat Size")), Null, cstr(rstImportData("Flat Size")))
Result: Throws error 94: Invalid use of Null
If I change the statement by removing the type conversion upon a false comparison:
IIF(IsNull(rstImportData("Flat Size")), Null, 0)
Result: Null
It returns Null as it should have the first time. It appears that I cannot do a type conversion in an IIF if the value passed in should ever be null even if it passes an IIF test, it still attempts to evaluate it at both the true and false answer. The only reason I'm using IIF like this is because I have a 25 line comparison to compare data from an Import against a matching record in a database to see if I need to append the prior to history.
Any thoughts? The way data is imported there will be null dates and where the spreadsheet import is in a string format I must convert either side to the other to compare the values properly but if either side is null this exception occurs :(
EDIT
Example of why I was using IIF (and considering using a universal function)
If master("one") <> import("one") Or _
master("two") <> import("two") Or _
master("date") <> import("date") Or _ //import("date") comes from a spreadsheet, it comes in as string, CAN be a null value
master("qty") <> import("qty") Or _ //import("qty") comes from spreadsheet, comes in as a string can CAN be null
master("etc") <> import("etc") Then
....stuff....
End If
This code expands for roughly 20 columns to compare in the database. I would prefer to check as part of the statement. I can think of a bunch of solutions but they involve adding much more code. If that is the case power to it, however I'm not one to give in so easily.
Options I see are
Creating temp vars to do the work prior to comparing and using these new vars instead of the recordset
Creating an object to pass the record into to preformat and work with, though extra work would provide this functionality to each import type since there are different files with similar fields
I'm here for ideas, and I'm open to any interesting pieces that can be thrown my way as I get to decide how to do it I'm looking for the most reusable approach.
The simple expedient of changing the value to a string helps tremendously. The trick is that trimming a string which is NULL will get a null string. Which can then be operated on as if it wasn't a database null.
I frequently use the form:
CInt("0" & Trim(SomeVariant & " "))
To get a valid number without having to go through a bunch of hijinks. The null is a nonentity for this problem.
The behavior you described is the standard way IIf operates under VBA. This is part of what Access 2003 Help says about it:
"IIf always evaluates both truepart and falsepart, even though it returns only one of them. Because of this, you should watch for undesirable side effects. For example, if evaluating falsepart results in a division by zero error, an error occurs even if expr is True."
However, if you use an IIf statement in a query, evaluation short circuits after truepart when expr is True --- falsepart is not evaluated in that case. Unfortunately this information is not useful for you ... unless you can incorporate a query into your comparison.
I don't know of any other way to avoid your error with IIf. I would try appending the Excel data into a table whose structure matches that of the table you will compare against, thereby eliminating the need to do a string conversion at the same time you do the comparison.
I have a textbox in my SSRS 2005 report. The expresssion for this textbox is:
=IIF(IsDBNull(Fields!fOrgID), Code.SetMyVar("null"), Code.SetMyVar(Fields!fOrgID.Value))
I have also tried IsNothing(Fields!fOrgID) and a few other variations of checking for nulls.
I have modified the SetMyVar function for testing and it now looks like this:
Public Function SetMyVar (var as String)
MsgBox(var, VbOKCancel, "Test1")
If var Is Nothing Then
Return "NOTHING"
Else
MyVar = var
Return var
End If
End Function
I also have the public variable MyVar:
Public Shared Dim MyVar as String
When my database query returns data, this correctly evaluates, a messagebox is displayed with the value, the textbox gets set with the value, and the world is generally a happier place.
When my database query does not return a value though, I get the error:
The query returned no rows for the data set. The expression therefore
evaluates to null.
and the SetMyVar function never appears to be ran (you never get the messagebox popup). As expected, my emotions range from anger, sadness, and bitter hatred of SSRS.
I read something about SSRS evaluating both sides of an IF statement, so perhaps that is why I get the error (likely then on Code.SetMyVar(Fields!fOrgID.Value))... not sure how I get around that though.
Thoughts? Suggestions? Words of comfort?
From the sound of things, it seems likely that the issue is that SSRS is having a problem displaying zero records. I'd recommend one of the following:
1) Use a control that handles zero records appropriately (Tables do. I think Lists do as well).
2) Modify your query to return a single record with blank values if it would otherwise return zero records.
An answer to the original question:
=IIF(IsNothing(Fields!fOrgID),
Code.SetMyVar("null"),
Code.SetMyVar(IIF(IsNothing(Fields!fOrgID),"Foo",Fields!fOrgID.Value)))
The error was from both sides of IIF being evaluated. The extra IIF in the statement above will avoid Code.SetMyVar from ever being called with a null value.
I believe you're right about about Iif always evaluating both of its value arguments (at least, it does in Visual Basic). I'm not sure why you're getting this precise error (unless strings can't be assigned a value of DBNull?), but you almost certainly want to attack this problem with a different method.
The reason for this is that your current code will likely always call both set methods regardless of the conditional value.
Formula that worked for my SSRS 2008 reports.
=IIf(String.IsNullOrEmpty(Fields!NullableFieldwithPossibleBlankStrings.Value),"Yes","No")
I tried this too (also tried a version with IsNothing)...
=Code.SetField(IsDBNull(Fields!fOrgID))
And changed the function to be one that accepts a boolean. I figure this above function would always return a true or false, but in the event of a NULL, I again get "The query returned no rows for the data set. The expression therefore evaluates to null.".
I need to pass back to my code if the field is null or not (as this will let me know if the datasource is null or not).
Let me know if you can think of a better way because I cannot.