Dynamic sql query with stored procedure and table variable - sql-server

I want to call a stored procedure dynamically as my names of the procedures are stored somewhere, also I need to store the result of that procedure into a table variable. Hence I had to write following sql code,
In following code
#tblEmailIds is the table variable which I want to store the result of SP in
#tempEmailSource is the name of the procedure
#tempRecipientsIdsCSV is the first argument that my SP is accepting
#ObjectMasterId is the second argument that SP is accepting (optional)
DECLARE #tempTypeName NVARCHAR(100),
#tempTypeId INT,
#tempEmailSource NVARCHAR(100),
#tempRecipientsIdsCSV NVARCHAR(MAX),
#tempIsObjectSpecific BIT,
#sqlQuery NVARCHAR(MAX) = 'INSERT INTO #tblEmailIds '
SELECT TOP 1 #tempTypeName = NAME,
#tempTypeId = Id,
#tempEmailSource = EmailListSourceName
FROM #tbleRecipientsTypes WHERE IsEmailIdsFetched = 0
SELECT #tempRecipientsIdsCSV = SUBSTRING(
(SELECT ',' + CAST(RT.EmailRecipientId AS NVARCHAR(50))
FROM #tbleRecipientsTypes RT WHERE RT.Id = #tempTypeId
ORDER BY RT.EmailRecipientId
FOR XML PATH('')),2,200000)
SELECT #tempRecipientsIdsCSV
SET #sqlQuery = #sqlQuery + 'EXEC ' + #tempEmailSource +' ' +'''' + #tempRecipientsIdsCSV +''''
IF (#tempIsObjectSpecific = 1)
BEGIN
SET #sqlQuery = #sqlQuery + ' ' + #ObjectMasterId
END
PRINT #SQLQUERY
EXECUTE SP_EXECUTESQL
#SqlQuery,'#IdsCSV NVARCHAR(MAX) OUTPUT,
#ObjectMasterId INT = NULL OUTPUT', #tblEmailIds
I am getting the following error
Msg 214, Level 16, State 3, Procedure sp_executesql, Line 6 Procedure
expects parameter '#params' of type 'ntext/nchar/nvarchar'.

There are quite a few problems here.
As the error message clearly states, the parameter list needs to be NVARCHAR so just prefix that string literal with an N (as also stated in #VR46's answer).
Table variables do not work the way that you are trying to use them. First, you do not ever declare #tblEmailIds, but even if you did, the scope of a table variable is local, and they cannot be used as OUTPUT parameters. Instead, you need to create a local temporary table (i.e. #tblEmailIds) and do INSERT INTO #tblEmailIds.
You reference another table variable, #tbleRecipientsTypes, that has not been declare or populated.
You do declare #tempIsObjectSpecific but never set it so it will always be NULL.
Why is #IdsCSV (in the sp_executesql call parameter list) declared as OUTPUT? Not only are you not passing in #tempRecipientsIdsCSV (to be #IdsCSV in the dynamic SQL), it isn't even necessary to be a parameter since you are directly concatenating the value of #tempRecipientsIdsCSV into the Dynamic SQL, and there is no #tempRecipientsIdsCSV variable in the Dynamic SQL to begin with. So remove #IdsCSV NVARCHAR(MAX) OUTPUT, from the parameter list.
You say that "#tempRecipientsIdsCSV is the first argument that my SP is accepting", but then you declare it in the code, which should result in an error.
What datatype is #ObjectMasterId? You say that it is passed into the proc and I see that it is concatenated into the Dynamic SQL, so it needs to either be a string type (i.e. not INT like is shown in the sp_executesql parameter list) or it needs to be in a CONVERT(NVARCHAR(10), #ObjectMasterId.
If #ObjectMasterId is being passed in, then why is it declared as OUTPUT in the sp_executesql parameter list? But the better question is probably: why are you even passing it into sp_executesql anyway since you directly concatenate it into the Dynamic SQL? There is no #ObjectMasterId variable being used in the Dynamic SQL.

Prefix N to the #params of SP_EXECUTESQL.
Also you need to store the result of OUTPUT parameter
Declare #IdsCSV NVARCHAR(MAX),#ObjectMasterId INT = NULL
EXECUTE SP_EXECUTESQL
#SqlQuery,
N'#IdsCSV NVARCHAR(MAX) OUTPUT,#ObjectMasterId INT = NULL OUTPUT',
#IdsCSV = #IdsCSV OUTPUT,
#ObjectMasterId = #ObjectMasterId OUTPUT

Related

Return variable using OPENQUERY

I am trying to make a simple function that reads a table from an ORACLE database and returns a sequence number. I would either like to return it directly or store the value inside of #cwpSeq and return that to the calling program.
Right now I am getting error:
RETURN statements in scalar valued functions must include an argument.
Can anyone assist me.
create function dbo.get_cwpSeq_from_oracle(#COIL nvarchar(100) )
returns int as
begin
DECLARE #cwpSeq int, #SQL nvarchar(1000);
set #SQL = N'select * from openquery(DEV, 'select cwp_seq from apps.custom_wip_pieces where lot_number = ''' + #COIL + '')';
return execute sp_executesql #SQL;
end;
As already mentioned, in this case you should use a procedure with an output parameter instead of a function. If you want to fully execute the query on the Oracle linked server side and return some value after that, I would suggest using dynamic as follows:
Create Or Alter Procedure dbo.get_cwpSeq
#COIL nvarchar(100),
#cwp_seq Int Output
As
Declare #QueryText nVarChar(max)
Select #QueryText = 'Select #cwp_seq=cwp_seq
From Openquery(DEV,
''Select cwp_seq
From apps.custom_wip_pieces
Where lot_number= ''''' + #COIL + ''''''') As Ora';
Execute sp_executesql #QueryText, N'#COIL nvarchar(100), #cwp_seq Int Output', #COIL = #COIL, #cwp_seq = #cwp_seq Output
As far as I understand in your case:
Linked server is "DEV", Owner of the table is "apps".

Save dynamic result from stored procedure into a dynamic table

I am facing some issues in saving the execution of stored procedure / scalar function into a table variable.
The function / stored procedure returns dynamic columns and I need to create a dynamic table to save the result of that function into it so that I can use the table.
Example: the stored procedure spGetEmployeeInfo could return employee name, employee id, etc. on such criteria they return only employee name,.
Is there a way to create a dynamic table and save the result into it after execute the stored procedure, or any suggestion.
Thanks
I don't like to get into this situation too often, but when I do, what I do is have the stored proc output into a global temp table. The name of the table is passed in as a parameter by the user. For instance:
create procedure dynamicBeCareful
#toggle bit,
#globalTempTableName varchar(50)
as
-- initializations
if left(#globalTempTableName,2) <> '##'
throw 50000, '#globalTempTableName must start with ##', 1;
declare #sql varchar(max);
-- build dynamic sql
if #toggle = 1
set #sql = 'select * into #tempTable from table1';
else
set #sql = 'select * into #tempTable from table2';
set #sql = replace(#sql, '#tempTable', #globalTempTableName);
-- terminations
exec (#sql);
declare #msg = 'Your results are in ' + #globalTempTableName;
print (#msg);
Then use it like this:
exec dynamicBeCareful 1, '##temp';
select * from ##temp;
Beyond just being dynamic in output, it also can get you out of nested insert-exec limitations.

Execute mixed sql: dynamic with static

I'm trying to execute mixed sql: dynamic with static. I have a stored proc with many queries and select-into-temp-table constructions. Portions of it need to be dynamic. Here are some extracted snippets of what I'm trying to do:
#DynamicPrefix = '0001' -- this is passed in by caller
#EngineCd = '070123456' -- this is passed in by caller
DECLARE #DynamicSQL VARCHAR(1000)
DECLARE #EngineKey INT
SET #DynamicSQL = 'set #EngineKey = (select optionnumber from lookup_' + #DynamicPrefix + '_option_001
where salescode = ' + #EngineCd + ')'
EXEC (#DynamicSQL)
Then further down:
Select MyCol
into #Eng
from myTable
where EngineKey = #EngineKey
There's a lot of static sql before, in between, and after my code block above.
The whole reason I'm bothering about dynamic sql is because I don't know certain table names until run time. So #DynamicPrefix enables me to construct the correct table names at execution time.
I can create the proc without errors, but when I run it I get the error Must declare the scalar variable "#EngineKey". It's clear to me that because #EngineKey is inside dynamic sql, it's invisible from within the static sql further down.
I suspect I need to use exec sp_executesql but I can't quite figure out the usage, so I had just started with EXEC.
How can I get this to work? Thanks in advance.
This should do the job:
#DynamicPrefix = '0001'; -- this is passed in by caller
#EngineCd = '070123456'; -- this is passed in by caller
DECLARE #EngineKey INT;
DECLARE #SQL NVARCHAR (MAX);
SET #SQL =N'set #EngineKey = (select optionnumber from lookup_'+
#DynamicPrefix +
'_option_001 where salescode = '+
#EngineCd +')';
EXECUTE sp_executesql
#SQL,
N'#EngineKey INT OUTPUT, #EngineCd VARCHAR(10)',
#EngineKey OUTPUT, #EngineCd;
You have to specify your output parameter with OUTPUT keyword, and set your variables and their datatypes as you can see in the code.
If you don't use the OUTPUT keyword, your variable will always return NULL.
There are examples provided in the docs, see sp_executesql.

SP_ExecuteSQL Generic stored_procedure call without output parameters, but catching the output

I'm scratching my head hard on this pb and I would like some help to figure out some solution.
Inside some TSQL programmable object (a stored procedure or a query in Management Studio)
I have a parameter containing the name of a stored procedure + the required argument for these stored procedures (for exemple it's between the brackets [])
Sample of #SPToCall
EX1 : [sp_ChooseTypeOfResult 'Water type']
EX2 : [sp_ChooseTypeOfXMLResult 'TABLE type', 'NODE XML']
EX3 : [sp_GetSomeResult]
I can't change thoses stored procedures (and I don't have a nice output param to cache, as I would need to change the stored procedure definition)
All these stored procedures 'return' a 'select' of 1 record the same datatype ie: NVARCHAR. Unfortunately there is no output param in those stored procedures definition (it would have been too easy otherwise :D)
So I'm working on something like this but I can't find anything working
DECLARE #myFinalVarFilledWithCachedOutput NVARCHAR(MAX);
DECLARE #SPToCall NVARCHAR(MAX) = N'sp_ChooseTypeOfXMLResult ''TABLE type'', ''NODE XML'';'
DECLARE #paramsDefintion = N'#CatchedOutput NVARCHAR(MAX) OUTPUT'
exec SP_executeSQL #SPToCall , #paramsDefinitions, #CatchedOutput = #myFinalVarFilledWithCachedOutput OUTPUT
-- my goal is to get something inside #myFinalVarFilledWithCachedOutput
Select #myFinalVarFilledWithCachedOutput
Any ideas ?
Here's an example of the syntax to take output of stored procedure that returns a selected value and pass that output to a table variable.
CREATE PROCEDURE tester
AS
BEGIN
DECLARE #var VARCHAR(10)
SET #var = 'beef'
SELECT #var
END
GO
DECLARE #outputtab TABLE ( varfield VARCHAR(100) )
INSERT #outputtab
( varfield )
EXEC tester
GO
SELECT *
FROM #outputtab
From there if you want to get it into a varchar variable:
DECLARE #outputvar VARCHAR(100)
SET #outputvar = ( SELECT TOP 1
*
FROM #outputtab
)

How do I run a query from a function, when the table name is passed in as argument

I am writing a function that would take table-name as argument.
I know the column name I need out of the table, but the table name + table owner is dynamically passed in (well I need that to be the case, but it is currently not working).
It kind of looks like this:
CREATE FUNCTION [myowner].
[alex_diff](#fromdate datetime, #todate datetime, #table_name varchar(256), #country_code varchar(3))
RETURNS int
AS
BEGIN
...
set #date_string = (select calendar_month2 from ??? where calendar_year=#current_year and country_code = #country_code)
...
END
I couldn't put #table_name in place of '???'
That gave me error:
Msg 1087, Level 16, State 1, Procedure alex_business_date_diff, Line
53 Must declare the table variable "#table_name".
What can I do to execute SQL on the dynamically passed table name?
I have tried doing the following:
set #statement = 'select #output=' + #column_name + ' from ' + #table_name + ' where calendar_year=' + cast(#current_year as varchar(4)) + ' and country_code = ' + #country_code;
EXEC sp_executesql #statement, N'#output varchar(31) OUTPUT', #date_string OUTPUT
But get this error (when I try to run the function):
Msg 557, Level 16, State 2, Line 1 Only functions and some extended
stored procedures can be executed from within a function.
You could use CLR in SQL Server and take advantage of the .NET language which would run dynamic sql.
You can create a stored procedure with all your dynamic manipulations and consume the result via output parameter.

Resources