sql server execute command in multiple server - sql-server

I have several link server on my server (about 20 servers). on these server exists a similar database and I want to execute a stored procedure on these server in depend of a parameter on my stored procedure on my server. I have following query for this idea.
Create procedure test
(
#ServerName VarChar(100),
#Code int
)
As
IF(#ServerName = 'Server1')Begin
Exec Server1.SGDB.dbo.DocInsert #Code
End Else IF(#ServerName = 'Server2')Begin
Exec Server2.SGDB.dbo.DocInsert #Code
End Else IF(#ServerName = 'Server3')Begin
Exec Server3.SGDB.dbo.DocInsert #Code
.
.
.
End Else IF(#ServerName = 'Server20')Begin
Exec Server20.SGDB.dbo.DocInsert #Code
End
End
Can I have a dynamic query with #ServerName parameter without using exec(string command).
thanks in advance.

You can replace the body of your stored procedure with this dynamic SQL:
declare #sql nvarchar(max)
set #sql = N'Exec ' + #ServerName + N'.SGDB.dbo.DocInsert #Code'
exec sp_executesql #stmt = #sql, #params = N'#Code int', #Code = #Code
It will be also better to declare the parameter #ServerName as NVarChar(128) to always work on Unicode characters and to allow for the maximum length of a linked server name.

Related

Run dynamic SQL Server stored procedure with linked server

This is a dynamic stored procedure that will pass the database, linked server and state. When executing this stored procedure, it runs the stored procedure on the database on the linked server and gives the results back.
Working code - here the linked server is absolute and not passed as a variable
EXECUTE MYPROC 'CA','MYDB'
CREATE PROCEDURE [dbo].[MYPROC]
(
#state varchar(2),
#DATABASE char(20)
)
AS
DECLARE #SQL #VARCHAR(MAX)
SELECT #SQL = 'use ' + #DATABASE + ';
SELECT * FROM pubs.dbo.authors WHERE state = #state'
EXEC MYLINKSERVER.master.dbo.sp_executesql
#SQL, N'#state char(2)', #state
Not working code: here the linked server is passed through a variable.
I get a "Syntax error" at #LINKEDSERVER**.**master
EXECUTE MYPROC 'CA','MYDB','MYLINKSERVER'
CREATE PROCEDURE [dbo].[MYPROC]
(
#state varchar(2),
#DATABASE char(20),
#LINKEDSERVER VARCHAR(20)
)
AS
DECLARE #SQL #VARCHAR(MAX)
SELECT #SQL = 'use ' + #DATABASE + ';
SELECT * FROM pubs.dbo.authors WHERE state = #state'
EXEC #LINKEDSERVER.master.dbo.sp_executesql
#SQL, N'#state char(2)', #state
Thanks in advance
Try this in your SP:
DECLARE #SQL VARCHAR(MAX);
SET #SQL = FORMATMESSAGE ( 'SELECT * FROM [%s].[%s].[dbo].[authors] WHERE [state] = ''%s'';', #LINKEDSERVER, #DATABASE, #state );
EXEC ( #SQL );
This would create the following SQL statement to be executed based on your sample parameters above:
SELECT * FROM [MYLINKSERVER].[MYDB].[dbo].[authors] WHERE [state] = 'CA';
I'm not sure what version of SQL Server you're running, so you may not be able to use FORMATMESSAGE, however, I'm sure you're familiar with concatenating strings.
I prefer to use OPENQUERY as it is usually much faster than using four-part query. So instead of SELECT * FROM [MYLINKSERVER].[MYDB].[dbo].[authors] WHERE [state] = 'CA';, try this:
SELECT * FROM OPENQUERY([MYLINKSERVER], '
SELECT * FROM [MYDB].[dbo].[authors] WHERE [state] = ''CA''
')
And your procedure will be something like this
CREATE PROCEDURE [dbo].[MYPROC]
(
#state CHAR(2),
#DATABASE VARCHAR(20),
#LINKEDSERVER VARCHAR(20)
)
AS
DECLARE #SQL NVARCHAR(500)
SET #SQL = N'SELECT * FROM OPENQUERY(' + QUOTENAME(#LINKEDSERVER) + ', ''
SELECT * FROM ' + QUOTENAME(#DATABASE) + '.dbo.authors WHERE state = ''''' + #state + '''''
'')'
EXEC SP_EXECUTESQL #SQL
--PRINT #SQL -- To see the final query to execute
Or you can use FORMATMESSAGE as the answer given by Critical Error.
SET #SQL = FORMATMESSAGE ('SELECT * FROM OPENQUERY([%s], ''
SELECT * FROM [%s].[dbo].[authors] WHERE [state] = ''''%s'''''');', QUOTENAME(#LINKEDSERVER), QUOTENAME(#DATABASE), #state
);
EXEC (#SQL);
Use QUOTENAME to avoid SQL injection. As the other parameter is limited to char(2), I guess it should be safe.

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

SQL Server sp_execute - Error with DateTime Variable in the Dynamic SQL

I tried to create dynamic SQL using sp_executesql, but it gives me this error message:
Msg 137, Level 15, State 2, Line 20
Must declare the scalar variable "#start".
Here is my stored procedure script
CREATE PROCEDURE sp_test (#start datetime, #end datetime)
AS
BEGIN
DECLARE #sql nvarchar(MAX)
SET #sql = 'SELECT * FROM table1 WHERE '
SET #sql = #sql + N'startDate BETWEEN #start AND #end'
EXEC sp_executesql #sql
Any input will be appreciated.
The below T-SQL should take care of your problem. Although, I would not recommend prefixing your stored procedure name with "sp_" since the system stored procedures use this naming convention. You wouldn't want to have your stored procedures confused with system stored procedures, or worse, Microsoft decides to name one of their future system stored procedures with the name of yours.
Things to note:
You define/declare all the custom parameters that you want to pass into your dynamic SQL statement in the #ParameterDefinition variable.
You add each of your custom variables to the sp_executesql call as if they were already part of the procedure.
IF OBJECT_ID('sp_test', 'P') IS NOT NULL DROP PROCEDURE sp_test
GO
-- ============================================================================
-- CALLING EXAMPLE:
-- EXEC sp_test '01/01/1901', '01/02/1901'
-- ============================================================================
CREATE PROCEDURE sp_test (#start datetime, #end datetime)
AS
BEGIN
DECLARE #sql nvarchar(max)
SET #sql = 'SELECT * FROM table1 WHERE '
SET #sql = #sql + N'startDate BETWEEN #start AND #end'
-- Build the Parameter Definition list for the dynamic SQL statement below
DECLARE #ParameterDefinition nvarchar(1000);
SELECT #ParameterDefinition = ''
+ ' #start datetime'
+ ',#end datetime'
EXEC sp_executesql
#statement = #sql
,#params = #ParameterDefinition
-- Assign values to any of custom parameters defined in #ParameterDefinition:
,#start = #start
,#end = #end
END
GO

Executing remote stored procedure within sp_executesql

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

Resources