I’m experiencing a frustrating issue when trying to call a proc in an OLE DB source task. I’m using the SQL command from variable data access mode but I can see that it isn’t evaluating my variable correctly.
My variable (with ValidateAsExpression set to True) uses an expression to create a sql command like “EXEC ProcName ‘Param'” where the value of Param comes from a variable who’s value I set using an EXEC SQL task. Below is the expression:
“EXEC ProcName ” + “‘” + #[User::vDateThreshold] + “‘”
If I use a variable in my source that references a static value it works fine, but the issue seems to be when I use a variable which reference another variable in its expression.
Has anyone else come across this issue?
I’m using this method because I’ve had a similar issue when trying to use a parameter with the sql command data access method.
Thanks in advance
I’m using this method because I’ve had a similar issue when trying to use a parameter with the sql command data access method.
The right way to do that is by using SQL Command with parameters:
EXEC ProcName ?
And select #[User::vDateThreshold] as parameter.
Parameterized OLEDB source query
If it is not working then check your procedure code and make sure it generate a specific result set. If the result set is dynamic and columns are not fixed then you have to define it in the query using WITH RESULTSETS keyword.
https://www.mssqltips.com/sqlservertip/2356/overview-of-with-result-sets-feature-of-sql-server-2012/
From the name of #[User::vDateThreshold it seems like an SSIS datetime variable. Try setting this to a variable with an explicit cast and then executing the stored procedure with the variable. Make sure there that are single quotes (') within the CAST function as you would use if this was done in SSMS. When concatenating a datetime variable within a string variable in SSIS, the datetime variable must be converted to text, which is done with (DT_STR, length, codepage) in the sample expression below. I'm not sure what version you're using, but testing this out on SSDT for Visual 2017 worked fine for me. This will cover if you still want to hold the SQL in a variable, however the solution that #Hadi posted is a good option if you'd prefer to go that route.
"DECLARE #pDate DATETIME
SET #pDate = CAST('" + (DT_STR, 50, 1252)#[User::vDateThreshold] + "' AS DATETIME)
EXEC ProcName #pDate"
Thank you for the responses to my question.
I actually found the issue was with the ordering of my tasks in the package. When I looked closer at the values assigned to the relevant variables by using a break point on my exec SQL task I could see the wrong date was being passed to my proc. When I set the value of vDateThreshold at an earlier point the correct date value was assigned.
I think this was a case of looking at something for long enough that I was missing the obvious.
Related
I have an Execute SQL Task which tries to execute a stored procedure, like this:
EXEC usp_stored_proc ?, ?, ? OUTPUT, ? OUTPUT;
I have 4 variables mapped to parameters. Ignoring the output parameters, these are both strings mapped to NVARCHAR params (as expected by the stored procedure).
When I run the package, an error tells me that execution failed with the message input string is not in the correct format. However, when I use a breakpoint to find the runtime values of the input parameters (or at least the variables mapped to them) and execute the same line of SQL in SSMS using the runtime values, it works fine.
Can anyone help? I'm at the end of my tether with this. I can't even find out the exact parameter causing the issue although it's probably both as the values follow the same format.
More details:
Connection type: OLE DB
Input Variable: String = schema.table
Mapped Param: NVARCHAR, ParamName = 0, ParamSize = -1
UPDATE
Solved the issue by making a new execute sql component that calls a stripped down procedure. I then slowly added lines of code to the procedure and additional parameters until arriving at the same component I started with and now it works. Comparing the original and rebuilt tasks, I see absolutely no differences (same with the procedure), so I don't know why this issue was occuring.
Try changing the parameter size (ParamSize) to match the parameter size within the stored procedure; if nvarchar(50) then set it to 50.
Solved the issue by making a new execute sql component that calls a stripped down procedure. I then slowly added lines of code to the procedure and additional parameters until arriving at the same component I started with and now it works. Comparing the original and rebuilt tasks, I see absolutely no differences (same with the procedure), so I don't know why this issue was occurring.
I defined a variable with the text of a parameterized query like this
select * from t where col = ?
Now, I am using that variable #[User::sqltext] in an OLE DB source for a dataflow task.
Problem is I don't see a way to set the parameters as I would have if I had supplied the SQL text in the source directly.
What am I missing?
A little touch.
Set your variable #[User::sqltext] with property EvaluateAsExpression=true, and set the following value for the Expression
"select * from t where col = '"+#[User::SomeStringParameter]+"'"
Handling expressions for variables is much easier with BIDSHelper, an addon for Visual Studio. It provides a special editor for managing variable expressions, as shown below.
This shows sample for similar task - creation of SQL command. Evaluate button allows to check results before it is executed in the package.
I am trying to get CSV IDs from a table from sql server and assign the result to a variable. below is the sql I have put inside the Execute SQL Task
set nocount on
declare #csv varchar(max) = ''
select #csv = #csv + cast(companyid as varchar(10)) + ',' from company where isprocessed = 0
select substring(#csv,1,len(#csv) - 1) as companyids
As you can see its a simple and standard way of getting csv of a field in t-sql. It works perfectly in query window but throwing below error when I run the Task in SSIS 2012
[Execute SQL Task] Error: The value type (__ComObject) can only be
converted to variables of type Object.
[Execute SQL Task] Error: An error occurred while assigning a value to
variable "sCSVCompanyIds": "The type of the value (DBNull) being
assigned to variable "User::sCSVCompanyIds" differs from the current
variable type (String). Variables may not change type during
execution. Variable types are strict, except for variables of type
Object. ".
Below are the settings of Execute SQL Task
In General tab, Resultset project is set to single row
In Result Set tab, Result Name is set to 0 (I also tried by setting it to csvids which is the alias column name in the select list) and Variable Name is set to User::sCSVCompanyIds
I have no clue why its not working. After wasting so much time I am worked out a hard way which by returning the result as Full Row set (same SQL which returns 1 row 1 column always) and add a for each loop container to loop throw the result set (which will always iterates only once for obvious reasons) and assign the result set's fields to the variable. It works for me but there should be easy way of doing it. What I am missing?
The problem is with the nvarchar(max) data type. I assume it will be same for varchar(max) also. Though relevant data types in SSIS are DT_NTEXT and DT_TEXT are present for some reason we are getting this error.
There are multiple options to handle this.
One Of course there might be more appropriate way to handle this by cast/converting the column within the query to fixed length instead of max something like cast(myvarcharmaxfield as varchar(8000)). In my case it doesn't work because I expect bigger length string. I am generating a csv string from a unique identifier column which itself is 36 chars long string and needs 3 extra chars for quoting them with signle quote and a comma as separator which will support only 205 values. So it doesn't work for me.
So I left with no option but to stick the way I implemented already which is in my question
After wasting so much time I am worked out a hard way which by
returning the result as Full Row set (same SQL which returns 1 row 1
column always) and add a for each loop container to loop throw the
result set (which will always iterates only once for obvious reasons)
and assign the result set's fields to the variable
The new way I learnt is from an unaccepted answer from this question
Change the Oledb connection to ADO.NET connection
I think this is fair enough but it requires me to create another connection manager (so that I don't have to change all existing tasks) and use it for this type of taks where I need csv but I did not buy it as I have very little time to doing research on creating connection string of it which appears to me with the type of erros I am getting is different from oledb.
I have a problem I just can't figure out, my Google-fu has failed me too, so I signed in just to get some expert help.
The problem is complex, with a few red herrings, for what I can figure out, plus as we deal with sensitive information, I can't give the exact code. Please bear with me, I'll try to be as precise and descriptive as I can.
Short version of the problem: I have a stored procedure (on a SQL Server 2008 R2 server) which returns one row when executed directly on the server. When the same stored procedure is executed via VB.net code (Visual Studio 2013 environment), one of the column's value is changed to DBNull.
Long version with code example:
Here is a cleaned up version of the stored procedure
Create PROCEDURE MySP
#inputParms [five of them]
AS
BEGIN
DECLARE #UserCanRun int
DECLARE #ThisApp INT
EXEC #UserCanRun = dbname.dbo.CheckUserCanRun #InputParm1, #ThisApp --security check
IF #UserCanRun = 0 --Means no problem, can continue
BEGIN
DECLARE #ExtraInfo varchar(100)
SELECT #ExtraInfo = typeID + ' - ' + typeName
FROM [three joined tables]
WHERE [conditions using some #InputParm4]
SELECT DISTINCT
col1, ..., [colN-1], #ExtraInfo as colN, [colN+1], ..., colM
FROM
[8 joined tables and subqueries]
WHERE
[more conditions with #InputParms2 to 5]
END
END
GO
This stored procedure runs just fine when executed directly on the database; it returns one row, with all the (available) info having their value set correctly. (You'll notice colN; it's the one giving me trouble; co-workers assure me the fact it is using value from a variable shouldn't be a problem.)
Now, when I call it from VB.net code:
dim rTable As DataTable
dim myCmd = New SqlCommand(SPName, myConnectionString)
dim parameter As SQLParameter
dim rValue As Integer = 0
[set SQL parameters]
If not myCmd is Nothing Then
If myCmd.Connection.State = connectionstate.Closed Then
[bit of security check code]
command.Connection.Open()
End If
Dim myAdapter As New SqlDataAdapter
myAdapter.SelectCommand = myCmd
myAdapter.Fill(rTable) 'problem!
ReturnValue = CInt(myCmd.Parameters(RETURN_VALUE_FIELD).Value)
End If
[more code]
If I do a quick watch on the rTable after the myAdapter.Fill command has executed, the value rTable.Rows(0).Item([M]) returns DBNull, while it was not DBNull when fetched directly in the SP, using exactly the same parameters.
I don't have a data set for that table; you can see it uses a generic DataTable (the code is adapted from an application specific object to simplify all stored procedure calls, so I can't create a dataset and use it at this level either). So I don't think.
I have checked for the validity of the value; I have even checked the Unicode value of each character of the #ExtraInfo value to make sure there was not some control character that would have been put in accidentally. It matched the value shown, so no bad character messing up the value.
This is used in a few places in the code, but seems to fail for one specific set of data on our production environment; I haven't been able to reproduce the problem on our development environment. So I can't just go in and play with it.
Would anyone know what else could cause a column's value to go from a non-null, non-empty varchar to DBNull by going through SqlDataAdapter.Fill()? I can't step into that call, so I am blind.
(Also worth of note, maybe: I have been using VB.net for only about two years, debugging existing systems, so I may be missing something obvious; although my more experienced colleagues don't understand it either.)
Edited to add the final word on the problem: I never found the solution, except good old Murphy's Law. After letting this aside for a while, I asked a co-worker to take a look. As I was showing him, the problem didn't occur. Another test later confirmed it was behaving normally. I can't promise anyone Murphy's law is a sure solution, but I can only suggest there was some transient error that disappeared on its own. If it happens to you, good luck, and please let us know if you find a solution, or even a way to diagnose it. Thank you!
Your stored procedure needs SET NOCOUNT ON at the beginning
I've run in to a problem with a software I'm configuring. I do not have access to the source code, only the config.
The issue is as follows, in the configuration the software expects me to enter a string, but I would like the string to jump out of the compare and instead execute a funtion.
Using sql profiler I get something like this:
exec sp_executesql N'SELECT * FROM dummyTable WHERE (Name LIKE #Pattern)',N'
This does not work in my setup, because pattern is not clearly defind in advanced. I need to take the
variable passed as pattern and run it trough a sql function but I can't figure out how. Typically Pattern contains a single char, in my example "1". I've tried altering the Pattern to use an escape char and run my function on it, but I think I'm missing someting (If this is at all possible).
The variable I've send from config is as follows:
{0}' or Name like dbo.RunCalulation({0})
Giving me the following:
'…#Pattern nvarchar(43)',#Pattern=N'1'' or Name like dbo.RunCalulation(1) '
This executes, but does not give any response, so I think the esacpe char does not work, and it compares the whole string to Name.
I'm real stuck at this, hope someone has a good idea what to do (I know that not having the source code is a real problem here.
One of the huge advantages of query parameters (such as #Pattern) is that they help protect against SQL injection (which is what you are trying to do).
So the answer is that you cannot do what you want. There's no way to escape the #Pattern parameter and add some of your own SQL to that query, because everything you pass as #Pattern will be interpreted as data, and never as SQL command text (which is the reason why your SQL text ends up inside the single quotes, and why your quote is automatically escaped to ''.).