SQL exec command using a string parameter - sql-server

I'm trying to call a system command within a procedure that also carries parameters. I get the following error:
Procedure expects parameter 'command_string' of type 'varchar'
Code:
ALTER PROCEDURE [dbo].[AddMSTRUser]
#LoginID nvarchar(120),
#Country nvarchar(120),
#FullName nvarchar(120)
AS
DECLARE #cmd varchar(max);
SET #cmd = CONCAT('MASysMgr.exe -w C:\User.smw -l "C:\cache.txt" -p "LoginID=' , #LoginID , '" "Country=',#Country,'" "FullName=',#FullName,'"')
EXECUTE master..xp_cmdshell #cmd;
This is how I call it:
EXEC AddMSTRUser #LoginID = 'Ugurcan.Kaya', #Country = 'VHQ', #FullName = 'Ugurcan Kaya'

Related

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 execute command in multiple 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.

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

calling one stored proc from another by executing command

In my stored procedure I have to pass a table and column name which may change everytime. So I build command and execute it. I want the output in another variable #curr_id. This store procedure will be called by second stored procedure by using #curr_id as input.
My problem is populating the #curr_id vriable. It is returned as zero. If I remove the
curr_id variable then it works(see commented line)
Can someone pl. tell me
- how to get #curr_id populated and returned as OUTPUT?
- how to call the first stored proc from a second stored proc?
ALTER PROCEDURE [dbo].[sp_astm_getcurrid]
#ColName as nvarchar(250),
#TblName as nvarchar(250),
#curr_id nvarchar(max) OUTPUT
AS
BEGIN
DECLARE #cmd nvarchar(max)
SET #cmd =N'SET '+#curr_id+'= SELECT MAX('+#ColName+') FROM '+#TblName;
--SET #cmd =N'SELECT MAX('+#ColName+') FROM '+#TblName;
EXEC (#cmd)
END
Because EXEC runs in a different context, it is not aware of your #curr_id variable. Instead, you can place the output of your dynamic SQL into a table variable, and then use that to set #curr_id.
Also, never start a stored procedure name with sp_.
ALTER PROCEDURE [dbo].[usp_astm_getcurrid]
#ColName as nvarchar(250),
#TblName as nvarchar(250),
#curr_id nvarchar(max) OUTPUT
AS
BEGIN
DECLARE #cmd nvarchar(max)
declare #dummy table (
ReturnColumn nvarchar(max)
)
SET #cmd = N'SELECT MAX(' + #ColName + N') FROM ' + #TblName;
insert into #dummy
(ReturnColumn)
exec (#cmd)
set #curr_id = (select ReturnColumn from #dummy)
END
Then, an example of calling this procedure from within another could be something like this. The important key is to use the OUTPUT keyword here in the call as well as in the declaration of the procedure above.
CREATE PROCEDURE CallMyProcedure
AS
BEGIN
declare #curr_id nvarchar(max)
exec dbo.usp_astm_getcurrid N'YourColumnName', N'YourTableName', #curr_id OUTPUT
select #curr_id
END
Friend Function execSP(ByVal spName As String, Optional ByVal params As Collection = Nothing) As Integer
Dim cmd As SqlCommand
Dim param As SqlParameter
Dim ret As Integer
Dim iParam As Integer
cmd = New SqlCommand
cmd.CommandText = spName
cmd.CommandType = CommandType.StoredProcedure
cmd.Connection = _sqlConn
cmd.CommandTimeout = 0
If Not params Is Nothing Then
For iParam = 1 To params.Count
param = params(iParam)
cmd.Parameters.Add(param)
Next
End If
If _sqlConn.State <> ConnectionState.Open Then
_sqlConn.Open()
End If
Try
ret = cmd.ExecuteNonQuery()
Catch ex As Exception
Throw New Exception(ex.Message)
Finally
_sqlConn.Close()
End Try
Return ret
End Function
You can use the OUTPUT parameter in sp_executesql:
ALTER PROCEDURE [dbo].[sp_astm_getcurrid]
#ColName as nvarchar(250),
#TblName as nvarchar(250),
#curr_id nvarchar(max) OUTPUT
AS
BEGIN
DECLARE
#cmd nvarchar(max)
SET #cmd =N'SELECT #curr_id_out = MAX('+#ColName+') FROM '+#TblName
EXEC sp_executesql
#cmd,
N'#curr_id_out nvarchar(max) OUTPUT',
#curr_id_out = #curr_id OUTPUT
END
I would be remiss not to mention that, in this case, using EXEC(#cmd) or sp_executesql(#cmd) leaves you vulnerable to SQL injection attacks.
I recommend adding something like the following to the beginning of the stored procedure:
SELECT
#ColName = REPLACE(
REPLACE(
REPLACE(#ColName, ';', ''), '-', ''), '''', ''),
#TblName = REPLACE(
REPLACE(
REPLACE(#TblName, ';', ''), '-', ''), '''', '')

Resources