Executing remote stored procedure within sp_executesql - sql-server

I'm trying to get IDENT_CURRENT value on the linked server. I've created a stored procedure sp_current_identity on the remote server that has output parameter.
CREATE PROCEDURE [dbo].[sp_current_identity] ( #strTableName nvarchar(255), #intRowId int OUTPUT )
AS
BEGIN
select IDENT_CURRENT(#strTableName)
END
After that I have created two synonyms:sp_current_identity and sometable.
I need to execute sp_current_identity using sp_executesql (I'm creating a custom DataAtapter to work with synonyms via LLBLGEN 3.1). Please see the following example:
declare #p4 int
set #p4=NULL
exec sp_executesql N'SET XACT_ABORT ON; INSERT INTO [db].[dbo].[sometable] ([FieldName], [TableName], [UserField]) VALUES (#p1, #p3, #p4) ;
exec dbo.sp_current_identity #p5, #p2
;SET XACT_ABORT OFF',N'#p1 varchar(50),#p2 int output,#p3 varchar(50),#p4 varchar(50), #p5 varchar(200)',
#p1='test24',#p2=#p4 output,#p3='test24',#p4='test5',#p5='sometable'
select #p4
It works fine when this code is executed on the remote server (where sp_current_identity is local stored procedure), but it causes an exception when the code is executed on the local server.
Here is the error:
Procedure or function 'sp_current_identity' expects parameter '#strTableName', which was not supplied.
Thanks for your help!

Have you considered running EXEC remoteserver.database.dbo.sp_executesql 'dynamic SQL'; instead of trying to execute the dynamic SQL locally? The sp_current_identity procedure has to exist at the place where the query is actually executed, not where the query is called from.

I found that I had to assemble my dynamic call to the remote server in two steps. I was trying to get the Database ID:
DECLARE #sql nvarchar(4000)
DECLARE #parmDefinition nvarchar(500)
SET #parmDefinition = N'#retvalOUTside int OUTPUT'
SET #sql = 'SELECT TOP 1 #retvalOUT = database_id FROM [' + #ServerName + '].master.sys.databases WHERE name = ''''' + #dbname + ''''''
DECLARE #SPSQL nvarchar(4000) = '
DECLARE #DBID INT;
DECLARE #parmDefinition nvarchar(500);
SET #parmDefinition = N''#retvalOUT int OUTPUT'';
DECLARE #SQLinside nvarchar(400) =''' + #sql + ''';
EXEC [' + #ServerName + '].master.dbo' + '.sp_executeSQL #SQLinside, #parmDefinition, #retvalOUT = #retvalOUTside OUTPUT'
EXEC sp_executeSQL #SPSQL, #parmDefinition, #retvalOUTside=#DBID OUTPUT

Related

SQL Server incorrect syntax exception when executing with sp_executesql

I am calling a procedure from a trigger and passing some parameters from trigger to procedure. Parameters are:
#table_name varchar(128), #where_str varchar(200)
Inside the procedure, I'm executing a command with sp_executesql. I think, I am using incorrect syntax, but I couldn't find the resolution.
This is the executed query:
SET #SqlString = N'update #ptable_name set RepSt=2 #pwhere_str';
SET #ParmDefinition = N'#ptable_name varchar(128), #pwhere_str varchar(200)';
execute sp_executesql #SqlString, #ParmDefinition,
#ptable_name = #table_name, #pwhere_str = #where_str;
Passed parameters are like that:
#table_name is [MyTable]
#where_str = N'where MyColumnA = '+#oldMyColumnA+N' AND MyColumnB = '+#oldMyColumnB+N' AND MyColumnC = '+#oldMyColumnC;
What you end up executing is something like:
DECLARE #ptable_name VARCHAR(128) = 'your_Table'
, #pwhere_str VARCHAR(200) = 'Your_where_clause'
UPDATE #ptable_name
SET RepSt=2
WHERE #pwhere_str
This doesn't work, you need to replace the variable in the executed sql:
SET #SqlString = N'update #ptable_name set RepSt=2 #pwhere_str';
SET #SqlString = REPLACE(REPLACE(#SqlString, '#ptable_name', #table_name), '#pwhere_str', #where_str)
execute sp_executesql #SqlString
(Very dirty, but this is the idea.)
SET #SqlString =N'update ' + #ptable_name + ' set RepSt=2 #pwhere_str';

Nested sp_executesql not working with output variable

I am trying to call a stored procedure (with output variable) using sp_executesql but within another stored procedure. I wrote the following, but still not able to get trhough what that error means
This would be called from webservice code:
exec sp1 'obj1',#params
Here obj and params are of nvarchar(max)
Definition of sp1 is :
Alter procedure [dbo].[sp1 ]
#procname nvarchar(max),
#params nvarchar(max)
as
declare #temp varchar(15)
if #procname = 'obj1'
begin
set #params = #params + ',#Newval varchar(15) output'
EXEC sp_executesql #sp2,#params,#Newval=#temp OUTPUT
end
Definition of sp2:
Here I am returning #Newval
Error I am getting :
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near ','.
Also in 2 in place of exec statement , I have tried following:
EXEC sp_executesql #sp2, #params, #temp OUTPUT;
Results in the same error.
set #sql='sp2,' + ' #params ' + ',#params,#temp OUTPUT'
EXEC sp_executesql (#sql)
Also results in the same error.
I need this dynamic selection of stored procedures in sp1 and params is a nvarchar(max) string of parameters and their values, some of them are varchar and are embedded in ''value'' format but this string is fine as I am able to call the underlying sp2 with this.
Additional info, it it helps.
EXEC sp_executesql #sp2,#params,#Newval=#temp OUTPUT
in this #params is combination of keys and vlaue pairs for the final sp. something like :
'#key1="a",#key2="b"'
and so on, I can not predefined the #params but it is dynamic and it is working
fine when I run it with
exec (#sql)
Format while whole of the name, params are embedded in the #sql
If #params='' or NULL then your , before #Newval is irrelevant. I suggest you to check:
IF NULLIF(#params,'') IS NULL or #params IS NULL
SET #params = '#Newval varchar(15) output'
ELSE
SET #params = #params + ',#Newval varchar(15) output'
You are passing #sp2 maybe you need this:
ALTER PROCEDURE [dbo].[sp1]
#procname nvarchar(max),
#params nvarchar(max)
AS
DECLARE #temp varchar(15)
IF #procname = 'obj1'
BEGIN
SET #params = #params + ',#Newval varchar(15) output'
EXEC sp_executesql N'EXEC sp2 #someparam1, #someparam2, #Newval varchar(15) OUTPUT', #params, #someparam1 = 1, #someparam2 = 2, #Newval=#temp OUTPUT
END
EDIT
Working example:
USE [AdventureWorks]
GO
DECLARE #procname nvarchar(max) = 'EXEC [dbo].[uspGetWhereUsedProductID] #StartProductID, #CheckDate',
#params nvarchar(max) = '#StartProductID int, #CheckDate date'
EXEC sp_executesql #procname, #params, #StartProductID = 1, #CheckDate = '2015-10-17'
GO

Calling stored procedure with OUTPUT parameter in dynamic SQL

I am calling a stored procedure with OUTPUT parameter using dynamic SQL.
set #cSql='EXEC '+#cName+'.dbo.uspNDateGet '''
+convert(varchar(10),#dtAsOn,102)+''','''
+#cBr+''','''
+#cLCode+''','''
+convert(varchar(10),#dtNDate,102)+''' OUTPUT'
exec(#cSql)
On executing the script, I get following error.
Cannot use the OUTPUT option when passing a constant to a stored procedure.
Without using dynamic SQL, the script gives me the required result.
EXEC uspNDateGet #dtAsOn,#cBr,#cLCode,#dtNDate OUTPUT
You need to pass parameters from outside into the inside query.
Here I show you the generic case:
declare #sql nvarchar(max);
declare #Out1 nvarchar(10);
declare #Out2 nvarchar(10);
declare #ParmDef nvarchar(max);
set #ParmDef =
' #Parm_Out1 nvarchar(10) '
+ ', #Parm_Out2 nvarchar(10) ' ;
set #sql='EXEC myproc #Parm_Out1 OUTPUT, #Parm_Out2 OUTPUT '
exec sp_executesql #sql, #ParmDef, #Parm_Out1 = #Out1, #Parm_Out2 = #Out2
In this particular instance, you don't actually need dynamic SQL at all.
You can parameterize the name of the stored procedure being called with EXEC, and pass the parameters normally. This is documented here:
DECLARE #dtNDate datetime, #procName nvarchar(386);
SET #ProcName = #cName + N'.dbo.uspNDateGet';
EXEC #procName
#dtAsOn = #dtAsOn,
#cBr = #cBr,
#cLCode = #cLCode,
#dtNDate = #dtNDate OUTPUT

How do you use OPENQUERY within sp_executesql?

I'm trying to verify a job number exists on a linked server and get back a variable (#JobExists) indicating whether it does or not (1 for yes, 0 for no).
To do this I'm trying to use OPENQUERY along with sp_executesql as I have to pass in a parameter for the job number. I've tried the code below but get the error 'Procedure expects parameter '#statement' of type 'ntext/nchar/nvarchar'. For testing purposes I've declared and set the variable #JobNumber.
DECLARE #JobNumber as varchar(50)
SET #JobNumber = '2112111'
DECLARE #JobExists as BIT
DECLARE #JobCount as int
DECLARE #ParmDefinition as varchar(100)
DECLARE #sql as varchar(500)
SET #JobExists = 0
SET #ParmDefinition = N'#Result int output'
SET #sql = 'SELECT #Result = SELECT COUNT(*) FROM OPENQUERY(MYLINKEDSVR,''SELECT JOB_NUMBER FROM PROD.tbl1 WHERE JOB_NUMBER = ''''' + UPPER(RTRIM(LTRIM(#JobNumber))) + ''''''')'
exec sp_executesql #sql, #ParmDefinition, #Result = #JobCount output
IF #JobCount > 0
SET #JobExists = 1
SELECT #JobExists
I've read up sp_executesql here: http://technet.microsoft.com/en-us/library/ms188001.aspx
I've also done various searches but haven't come across any answers that work for me.
Is there something I'm missing?
The error message is clear: you must declare #sql as nvarchar and not as varchar.
The same for #ParamDefinition:
DECLARE #ParmDefinition as nvarchar(100)
DECLARE #sql as nvarchar(500)

Can I specify a database name dynamically in a trigger?

I need to get data from a table in a database who's database name will be determined as a variable during a trigger. I then, knowing this variable need to get a seqno from a table in the determined database for a item which was also determined as a variable during a trigger.
I am trying this route as I assume I need to build the SQL statement before I set it to a variable.
This is not working and I need to know the best way on how I can do this:
DECLARE #SU_SEQNO INTEGER, #SU_NAME VARCHAR(50), #SU_OWNER VARCHAR(15), #SUD_SEQNO INTEGER, #SQL NVARCHAR(500)
SET #SU_OWNER = 'XXX'
SET #SU_NAME = '1ABC234'
SET #SQL ='SELECT #SUD_SEQNO=SEQNO FROM ' + (#SU_OWNER) + '.SU_MAIN
WHERE UNITNAME= ' + #SU_NAME
SET #SUD_SEQNO = (EXECUTE (#SQL))
Thanks alot for any help with this
From: Get result from dynamic SQL in stored procedure
SET #SQL = N'SELECT DISTINCT #FiscalYear = FiscalYear FROM ' + #DataSource;
EXEC sp_executesql #SQL, N'#FiscalYear INT OUTPUT', #FiscalYear OUTPUT;
PRINT #FiscalYear;
I'd re-engineer to use the sp_executesql method as shown above. That should do the trick.
I have amended the code, and it works
declare #su_owner varchar(15) = 'DBTEST'
declare #SU_SEQNO INTEGER=1, #SUD_SEQNO INTEGER=0, #SQL NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500), #SU_NAME_INPUT VARCHAR(50)='SU123'
SET #SU_NAME_INPUT = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SU_NAME = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SQL = N'SELECT #sud_seqnoOUT=MAX(SEQNO) FROM ' + quotename(#su_owner) + '.[dbo].[SU_MAIN] WHERE UNITNAME]=#SU_NAME_INPUT' ;
SET #ParmDefinition = N'#SU_NAME_INPUT VARCHAR(50),#sud_seqnoOUT INT OUTPUT'
EXEC sp_executesql #SQL,#ParmDefinition,#SU_NAME_INPUT = #SU_NAME,
#sud_seqnoOUT = #SUD_SEQNO OUTPUT

Resources