SSIS: How do I pass string parameter in an update statement in Execute SQL Task? - sql

I have one execute SQL Task in SSIS 2012 which has update statement. I want to pass a string variable in the where clause of this update statement. The update section is as below:
where coalesce(s1.iteration, '') not like '%?%' and s2.Iteration = '?'
Here, ? needs to be replaced with a string variable, which in this case would be 08152017. I have added the variable to the Parameter Mapping. Screenshot is attached.
The task executes successfully but does not updates the value in the intended column. It seems the query is not passing the value.What am I doing wrong? How do I check that the SQL inside the Execute SQL Task is actually getting the value from the variable?

First of all, when you set your variable in parameter mapping, make sure the datatype is NVARCHAR and not LONG.
Second you need to write your statement like this:
where coalesce(s1.iteration, '') not like '%?%' and s2.Iteration = ?
You dont need '' because your variable is already set as a string.
Try to hardcode your value in your variable to see if it passes. Otherwise, set a breakpoint on pre-execute to see wheter your variable has a value.
If your variable has a value and your SQL is not working, maybe you should look into your SQL. Maybe try it directly in SSMS to see if it actually runs or does anything.

In scenario ? is Integer type variable, then please use below format:
SELECT ? +' Hello World!'
The above does not require the use of an additional string variable.

Create a user variable with % on it, for example, variable name is Like_Var with data type String
"%" + #Orig_Var + "%"
Let's say, Orig_Var has a value of 08152017, therefore Like_Var will have %08152017%
Then use Like_Var on your parameter in Execute SQL Task as parameter 0, data type VARCHAR in Parameter Mapping
WHERE COALESCE(s1.iteration, '') NOT LIKE ?
AND s2.Iteration = ?

Related

How do I add parameters to my queries when using clr/c++ for multiple variables

I want to be able to add parameters to my queries to make my statements less vunerable to sql injections
My code (Key parts are surrounded by ** as I cannot make code bold)
OleDbConnection^ existingSqlConnection = nullptr;
existingSqlConnection = gcnew OleDbConnection("Provider = Microsoft.ACE.OLEDB.12.0;" +
"Data Source =" + "myDatabaseV3.accdb");
**String^ sqlText = "SELECT * FROM #tableName WHERE #fieldName = #fieldEntityName";
OleDbCommand^ dbCommand = gcnew OleDbCommand(sqlText, existingSqlConnection);
OleDbParameterCollection^ paramCollection = dbCommand->Parameters;
dbCommand->Parameters->Add(gcnew OleDbParameter("#tableName", tableName->ToString()));
dbCommand->Parameters->AddWithValue("#fieldName", field);**
dbCommand->Parameters->AddWithValue("#fieldEntityName", fieldEntity);
**Console::WriteLine(dbCommand->CommandText);
Console::WriteLine(paramCollection->Count);**
existingSqlConnection->Open();
OleDbDataReader^ reader = dbCommand->ExecuteReader(System::Data::CommandBehavior::CloseConnection);
return reader;
The output for this is
SELECT * FROM #tableName WHERE #fieldName = #fieldEntityName
3
Which clearly shows that there are 3 parameters but they are not being added to my query which is the problem I want to be solved
This is not how parameters work. They are not replacement values for text templates. Parameters are a mechanism to pass in a value to the variable in the query, just like passing a parameter to a stored procedure will pass that value in to be used as a variable in the query.
Along these lines, parameters can only be used where variables can be used in queries. And, variables cannot be used for object names, which is why people resort to using SQL Injection when the table and/or column name(s) need to change. In your example code:
#tableName could never be a variable in a query, hence it cannot be a parameter
#fieldName could never be a variable in a query, hence it cannot be a parameter
#fieldEntityName if it is supposed to be a value and not a column name, can be a parameter, in which case it will remain as #fieldEntityName in the query, and it will have a value of fieldEntity.
Please see the second option of my answer on your related question for how to prevent SQL Injection (short answer: sanitize inputs).
Also, using AddWithValue() is a bad practice. Create the parameter with the intended max size, then give that a value, and finally add it to the parameters collection. You do not want it to auto-detect the max size for the parameter as it will use the first value it gets, and any subsequent value that is longer will be silently truncated.

Execute SQL Task -Full Result Set Datatype Mismatch Error

I am creating an SSIS package which has an execute SQL task and it passes result set variable to a for each loop container.
My Sql Query is:
Select distinct code from house where active=1 and campus='W'
I want the execute sql task to run this query and assign its results to a variable which is passed to a for each loop container which should loop through all the values in the result set.
But my execute sql task fails with error:
The type of the value (DBNull) being assigned to variable
"User::house" differs from the current variable type (String)
Now i have done my research and i have tried assigning the variable datatype Object but did not work. I tried using cast in my sql query and that also did not work.
Since my query returns multiple rows and one column, i am not sure how i can assign a datatype to the whole query?
Sample:
Code
AR
BN
CN
It sounds like you have a variety of issues in here.
Result Set
The first is in your Execute SQL Task and the need for agreement between the Result Set specification and the data type of the Variable(s) specified in the Result Set tab. If you specify Full Resultset, then the receiving object must be of type System::Object and you will only have 1 result set. The type of Connection Manager (ODBC/OLE/ADO) used will determine how you specify it but it's infinitely searchable on these fine forums.
The other two options are Single Row and XML. In 13 years of working with SSIS, I've never had cause to specify XML. That leaves us with Single Row. For a Single Row Result Set, you need to provide a variable for each column returned and it needs to be correctly typed.
To correct your issue, you need to declare a second variable. I usually call my rsObject (record set object) and then specify the data type as System.Object.
For Each Loop Container
Your For Each Loop Container will then be set with an Enumerator of "Foreach ADO Enumerator" and then the ADO object source variable will become "User::rsObject"
In the Variable Mappings, you'll specify your variable User::house to index 0.
Testing
Given a sample set of source source data, you can verify that you have your Execute SQL Task correctly assigning a result set to our object and the Foreach Loop Container is properly populating our variable.
SELECT DISTINCT
code
FROM
(
VALUES
('ABC', 1, 'w')
, ('BCD', 1, 'w')
, ('CDE', 0, 'w')
, ('DEF', 1, 'w')
, ('EFG', 1, 'x')
) house(code, active, campus)
WHERE
active = 1
AND campus = 'w';
If you change the value of campus from w to something that doesn't exist, like f then things will continue to work.
However, the error you're receiving can only be generated if the code is a NULL
Add one more entry to the VALUES collection like
, (NULL, 1, 'w')
and when the For Each Loop Container hits that value, you will encounter the error you indicate
The type of the value (DBNull) being assigned to variable "User::house" differs from the current variable type (String)
Now what?
SSIS variables cannot change their data type, unless they're of type Object (but that's not the solution here). The "problem" is that you cannot store a NULL value in an SSIS variable (unless it's of type object). Therefore you need to either exclude the rows that return a NULL (AND code IS NOT NULL) or you need to cast the NULL into sentinel/placeholder value as a substitute (SELECT DISTINCT ISNULL(code, '') AS code). If an empty string is a valid value, then you need to find something that isn't - "billinkcisthegreatestever10123432" is unlikely to exist in your set of codes but that might be a bit excessive.
Finally, think about renaming your SSIS variable from house to code. You might be able to keep things straight but some day you'll hand this code over to someone else for maintenance and you don't want to confuse them.
A picturesque answer https://stackoverflow.com/a/13976990/181965
the variable "User::house" is string , so , did you use it in result set?
you need declare son "object" var for result set
result set
then declare a string variable for every single Code from your result
For Each Loop Container
good luck

Compare parameter in WHERE clause stored procedure

I have a stored procedures which receives a list of ItemId's. If the list only contain one item this works:
AND (#OrgItemIds = -1 OR ...)
AND (#OrgItemIds = -1 AND...)
but if the list contains more than one item it crashes.
Anybody knows how to fix this? Can I check the size of the list somehow?
Or can I check just the first element of the list like #OrgItemIds[0] or something like that?
There is no "comma-separated set of values" or "array" datatypes in SQL SERVER. You handle the parameter as a scalar variable in your code. Thus when you provide a single value in that list, server implicitly converts it to int and your sp succeeds.When you provide string with commas - it becomes impossible to convert it to int.You have to manually parse your argument, put it into a table variable and then use this table in WHERE clause. Or change handling of this argument to support a string of values instead of scalar value:
... where #OrgItemIds like '%,' + cast(t.OrgItemIds as varchar(10)) + ',%'
which is much worse for performance than filtering by id or list of ids.

SSIS to handle SQL binary data type

I am strugling wiith handling a sql binary(8) data type.
No matter what I try to do with it inside the SSIS package, it always fails with an error of: "Invalid cast specification"
Let me describe what I am tying to do in details:
I have a single row that I am assigning to a variable in a SQL Task in the control flow.
select max(LastRowVersion as bigint) as MinRV from MyTable
LastRowVersion is of datatype binary(8).
2.Then I am assigning the result to variable - User::MaxRowVersion
If I configure MaxRowVersion to be of String or Object data type, then this part works fine.
3.Next I am opening a data flow task with the following select statement:
select fields
from AnotherTable
where LastRowVersion > ?
and assigning User::MaxRowVersion to the query.
Again LastRowVersion is of datatype binary(8) in the table - AnotherTable.
Here is where I am getting the error that I mentioned above.
I have tried various types of playing with the DT_BYTES cast type in the expression of the User::MaxRowVersion variable, but it is failing.
I have also read that there is a possibility to open a C# script task to handle it or that Dynamic SQL can help, but I would rather keep the solution as simple as possible with no scripting if possible.
Thanks for the help,
Dani
Have you tried this?
Keep MaxRowVersion as a Sting data type
Cast the variable reference in the SQL statement
Example:
"
SELECT my_field
FROM my_table
WHERE LastRowVersion > CAST('" + #[User::MaxRowVersion] + "' as MyDataType);
"

Convert String Variable to Datetime Returns Incorrect Value in SSIS

Following my question in https://stackoverflow.com/questions/7387418/where-clause-using-date-taken-from-string-variable-sent-out-incorrect-return-in-s, this is the simplified version of the question:
The query used for the OLE DB Source is this, with a string type variable inside:
select
*
from
A
where
A.A_IN_DATETIME < CONVERT(DATETIME,?,105) and
(A.A_OUT_DATETIME is NULL or A.A_OUT_DATETIME >= CONVERT(DATETIME,?,105))
The query above works inside a Foreach Variable Enumerator, with the variable used is an array of string variable consisting of this: 13-09-2011,12-09-2011,11-09-2011,10-09-2011,09-09-2011,08-09-2011,07-09-2011,06-09-2011,05-09-2011,04-09-2011,03-09-2011,02-09-2011,01-09-2011
The condition for the problem is this: For example, there is a record in A with A_IN_DATETIME = 2011-09-12 (YYYY-MM-DD format) and A_OUT_DATETIME = NULL.
The correct result for the query above that it should have been only returning values for 13-09-2011 and the rest return 0 records, but in the execution, there was a result for 12-09-2011 to 10-09-2011 also. I don't know if the SSIS somehow mistaken the 12-09-2011, 11-09-2011, 10-09-2011 to 09-12-2011,09-11-2011,09-10-2011 (FYI, I've checked the parsing result and also the loop enumerator by printing it out in a message box generated from the script task, and it is still in its correct form).
Is there any solution for this problem?
Run Sql Profiler and see what query comes through to SQL Server. This will allow you to re-run the exact query in SSMS and see the results right there.
I don't believe conversion to DATETIME accepts a format, i.e. 105.Try this instead:
CONVERT(DATETIME, '9/13/2011 15:37:00')
Result is DATETIME - 2011-09-13 15:37:00.000