Using OUTPUT Parameters within Dynamic SQL within Stored Procedures- Possible? - sql

I have a SP that I have created to check for validations and return an OUTPUT Parameter of 0 (No Error) or 1 (Error). However, I have to run this SP within Dynamic SQL since it will be ran through a loop of different data.
Can I pull the OUTPUT from the SP through the EXEC sp_executesql #SQL?
I can not post the actual code, but I can give an example..
DECLARE
#SQL nVARCHAR(4000),
#SPName VARCHAR(200),
#Parm1 VARCHAR(100),
#Parm2 VARCHAR(100),
#Parm3 VARCHAR(100),
#ParmDefinition nVARCHAR(400),
#Error nVARCHAR(1)
SELECT
#SPName = 'spExample1',
#Parm1 = '000000',
#Parm2 = '111111',
#Parm3 = '#Err=#Error OUTPUT',
SET #SQL = 'EXEC ' + #SPName + ' ' + #Parm1 + ',' + #Parm2 + ',' + #Parm3 + '
SET #ParmDefinition = N'#Err2 nVARCHAR(1) OUTPUT'
EXEC sp_executesql #SQL, #ParmDefinition, #Err2=#Error OUTPUT
The #SQL Variable ends up being:
EXEC spExample1 000000, 111111, #Err=#Error OUTPUT
^^Which works perfectly by itself.
Basically I'm trying to get the OUTPUT through the above code, but when it's ran through Dynamically.
Is this possible or is there another way to do this?
The way things kind of play out in the end appear to be:
EXEC sp_executesql EXEC spExample1 000000, 111111, #Err=#Error OUTPUT, #Err2 nVARCHAR(1) OUTPUT, #Err2=#Error OUTPUT
After looking at that it looks ridiculous, however any help would definitely be appreciated.

Sorry for the delay :D, the following code works perfectly (For N.. output and input parameters) please try this (source):
CREATE PROCEDURE Myproc
#parm varchar(10),
#parm1OUT varchar(30) OUTPUT,
#parm2OUT varchar(30) OUTPUT
AS
SELECT #parm1OUT='parm 1' + #parm
SELECT #parm2OUT='parm 2' + #parm
GO
DECLARE #SQLString NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #parmIN VARCHAR(10)
DECLARE #parmRET1 VARCHAR(30)
DECLARE #parmRET2 VARCHAR(30)
SET #parmIN=' returned'
SET #SQLString=N'EXEC Myproc #parm,
#parm1OUT OUTPUT, #parm2OUT OUTPUT'
SET #ParmDefinition=N'#parm varchar(10),
#parm1OUT varchar(30) OUTPUT,
#parm2OUT varchar(30) OUTPUT'
EXECUTE sp_executesql
#SQLString,
#ParmDefinition,
#parm=#parmIN,
#parm1OUT=#parmRET1 OUTPUT,#parm2OUT=#parmRET2 OUTPUT
SELECT #parmRET1 AS "parameter 1", #parmRET2 AS "parameter 2"
go
drop procedure Myproc

I haven't tested this in depth, but I did note the following:
When calling stored procedures, you can't mix-and-match named and not-named parameters. So instead of
EXEC sp_executesql #SQL, #ParmDefinition, #Err2=#Error OUTPUT
use
EXEC sp_executesql #SQL, #ParmDefinition, #Error OUTPUT
but, since the output parameter defined for sp_executesql is #Err2, it needs to be
EXEC sp_executesql #SQL, #ParmDefinition, #Err2 OUTPUT
This should work.

Related

Dynamic SQL with parameters

I have a SQL query stored in a table that contains parameter names. I need to know how to execute it properly in a stored procedure.
This is my SQL code in the procedure
PROCEDURE [spMassUpdateSKUs]
#SKU AS NVARCHAR(20)
,#FIELD AS NVARCHAR(50)
,#VALUE AS NVARCHAR(50)
,#RESULT as Int = Null Output
AS
BEGIN
IF EXISTS(SELECT CODENUMBER FROM INVENTORY_MASTER WHERE CODENUMBER=#SKU)
BEGIN
DECLARE #SQLQUERY AS NVARCHAR(50)
SET #SQLQUERY=(SELECT SQLUPDATE FROM MASS_UPDATE WHERE DROPDOWNLABEL=#FIELD)
EXEC SP_EXECUTESQL #SQLQUERY
END
and this is the sql query from the table
update inventory_master_flex set departmentid=#value where codenumber=#sku
I've tried replacing with the real parameters but that doen't work.
SELECT REPLACE(REPLACE(#SQLQUERY,'#VALUE',#VALUE),'#SKU',#SKU)
-- 50 is too short for sure; you may try 1000 or different number
DECLARE #SQLQUERY AS NVARCHAR(MAX)
-- for debug purpose
PRINT #SQLQUERY
-- params
EXEC SP_EXECUTESQL #SQLQUERY, N'#Value NVARCHAR(50), #sku NVARCHAR(50)`, #Value, #sku
REPLACE is not good in case of strings with quotes and so on which would brake the #sqlquery code.
Pass the parameters in using sp_executesql, not replace():
IF EXISTS(SELECT CODENUMBER FROM INVENTORY_MASTER WHERE CODENUMBER=#SKU)
BEGIN
DECLARE #SQLQUERY AS NVARCHAR(MAX);
SET #SQLQUERY = (SELECT SQLUPDATE FROM MASS_UPDATE WHERE DROPDOWNLABEL = #FIELD);
EXEC SP_EXECUTESQL #SQLQUERY, N'#SKU VARCHAR(255), #VALUE VARCHAR(255)', #SKU = #SKU, #VALUE = #VALUE
END;
I don't know what the types are. But if one or both are strings or dates, then you would need single quotes in your implementation. However, you are already using sp_executesql so go whole-hog and pass in parameters as well.

Execute Stored Procedure from Stored Procedure w/ dynamic SQL capturing output

Inside a stored procedure (A) I need to call a stored procedure (X) inside a specific database and capture the output. X returns a single value.
From what I understand I need to provide the DB name of X to the stored procedure in A and I need to use dynamic SQL to build the query on execution targeting the desired database.
What am unable to figure out is how to capture output from X in A to work with the result.
You could use sp_executesql to dynamically call your nested Stored Procedure.
DECLARE #db AS SYSNAME
DECLARE #return_value AS INT
DECLARE #output_value AS INT
DECLARE #sql AS NVARCHAR(MAX)
-- Set your DB name
SET #db = N'mydb'
/*
Use sp_executesql to dynamically pass in the db and stored procedure
to execute while also defining the values and assigning to local variables.
*/
SET #sql = N'EXEC #rtn = ' + #db + '.dbo.[your_stored_procedure] #output OUTPUT'
EXEC sp_executesql #sql
, N'#rtn AS INT, #output AS INT OUTPUT'
, #return_value = #rtn
, #output_value = #output OUTPUT
Adding to the above answer, following is the way to call stored procedures dynamically by passing parameters.
DECLARE #SpName VARCHAR(1000)
SELECT #SpName = DeleteLiveSP FROM dbo.ArchivalInfo (NOLOCK) WHERE TableName = #TableName
DECLARE #SqlString nvarchar(2000)
DECLARE #ParamDef nvarchar(2000)
SET #SqlString = N'exec '+#SpName + ' #CriteriaParam'
SET #ParamDef = N'#CriteriaParam XML'
EXECUTE sp_executesql #SqlString ,#ParamDef, #CriteriaParam = #Criteria

Is it possible to supply sp_ExecuteSql parameter names dynamically?

Is it possible to supply the list of parameters to sp_ExecuteSql dynamically?
In sp_ExecuteSql the query and the parameter definitions are strings. We can use string variables for these and pass in any query and parameter definitions we want to execute. However, when assigning values to the parameters, we cannot seem to use strings or string variables for the parameter names.
For example:
DECLARE #SelectedUserName NVARCHAR(255) ,
#SelectedJobTitle NVARCHAR(255);
SET #SelectedUserName = N'TEST%';
SET #SelectedJobTitle = N'%Developer%';
DECLARE #sql NVARCHAR(MAX) ,
#paramdefs NVARCHAR(1000);
SET #sql = N'select * from Users where Name LIKE #UserName '
+ N'and JobTitle LIKE #JobTitle;'
SET #paramdefs = N'#UserName nvarchar(255), #JobTitle nvarchar(255)';
EXEC sp_ExecuteSql #sql, #paramdefs, #UserName = #SelectedUserName,
#JobTitle = #SelectedJobTitle;
The query #sql, and the parameter definitions, #paramdefs, can be passed into sp_ExecuteSql dynamically, as string variables. However, it seems to me that when assigning values to the parameters we cannot assign dynamically and must always know the number of parameters and their names ahead of time. Note in my example how I could declare parameters #UserName and #JobTitle dynamically and pass in that declaration as a string variable, but I had to explicitly specify the parameter names when I wanted to set them. Is there any way around this limitation?
I would like to be able to both declare the parameters dynamically and assign to them dynamically as well. Something like:
EXEC sp_ExecuteSql #sql, #paramdefs,
N'#UserName = #SelectedUserName, #JobTitle = #SelectedJobTitle';
Note that this doesn't actually work but illustrates the sort of thing I'd like to happen. If this sort of thing worked then I could pass in different queries with different numbers of parameters which have different names. The whole thing would be dynamic and I wouldn't have to know the names or numbers of parameters beforehand.
You can do this by using a table valued parameter as the only parameter:
DECLARE #YourQuery NVARCHAR(MAX0 = '<your dynamic query>'
CREATE TYPE dbo.SqlVariantTable AS TABLE
(
[Name] VARCHAR(255),
Type VARCHAR(255),
Value SQL_VARIANT
)
DECLARE #Table SqlVariantTable;
-- Insert your dynamic parameters here:
INSERT INTO #Table
VALUES
('Parameter1', 'VARCHAR(255)', 'some value'),
('Parameter2', 'INT', 3),
DECLARE #ParameterAssignment NVARCHAR(MAX)
SELECT #ParameterAssignment = ISNULL(#ParameterAssignment + ';','') + 'DECLARE ' + Name + ' ' + Type + ' = (SELECT CAST(Value AS ' + Type + ') FROM #p1 WHERE Name = ''' + Name + ''')'
FROM #Table
SET #YourQuery = #ParameterAssignment + ';' + #YourQuery
EXEC SP_EXECUTESQL #YourQuery, N'#p1 SqlVariantTable READONLY', #Table
Now you can simpy insert the parameters into the #Table variable, and they will be present with they original name and type within the query exeuted in the SP_EXECUTESQL. Only make sure you do not use VARCHAR(MAX) or NVARCHAR(MAX) variable types, since they are not supported by SQL_VARIANT. Use (for instance) VARCHAR(4000) instead
I also thought about this and couldn't find anything better than this:
BEGIN
DECLARE
#p1 int, #p2 int, #p3 int, #p4 int...;
DECLARE
#DynamicSQL NVARCHAR(MAX);
SET
#p1 = {some logic},
#p2 = {some different logic},
#p3 = {another logic},
#p4 = {yet another logic},
...;
SET
#DynamicSQL =
N'
some statement
doing
somethin
WHERE
someColumn = #p1
AND someAnotherColumn = #p2
/*no more parameters used below this line*/
';
exec sp_executesql
#stmt = #DynamicSQL,
#params = '#p1 int, #p2 int, #p3 int, #p4 int...'
#p1 = #p1, #p2 = #p2, #p3 = #p3, #p4 = #p4, ...
END;
Notice, that #DynamicSQL uses only 2 out of the 4 possible parameters. Parameters #p1 int, #p2 int, #p3 int, #p4 int... represent the maximum number of parameters you can use in your #DynamicSQL.
You have to have a predefined maximum number of parameters that can be used, and you build the #DynamicSQL statement only with some subset of them. Parameters defined in #params that are not present in the #stmt statement are ignored.
It is not 100 % universal, but I guess that using more than 200 dynamic parameters smells of code smell.
You're trying to work one level too high in abstraction.
Arbitrary parameters requires dynamic SQL, a.k.a. building SQL via strings, which then makes the entire point of parameters moot.
Instead, this should be handled as parameters in the calling code, such as C#, which will allow you to take any SQL statement in a string, apply an arbitrary number of arguments, and execute it.
While this doesn't answer my question I thought it may be useful for others in similar situations. I've discovered the following:
If you have a fixed number of parameters but don't know their names you can pass the parameter values by position rather than name. The following will work:
exec sp_ExecuteSql
#sql,
#paramdefs,
#SelectedUserName, #SelectedJobTitle;
or
exec sp_ExecuteSql
#sql,
#paramdefs,
N'TEST%', N'%Developer%';
Please try this.
Declare #UName varchar(50)
Declare #Job varchar(50)
Set #UName = 'TEST%'
Set #Job = '%Developer%'
exec sp_ExecuteSql #sql, #paramdefs, #UserName = #UName, #JobTitle = #Job;
May this will help you.
Ref From technet.Microsoft.com
Ex.
DECLARE #IntVariable int;
DECLARE #SQLString nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
/* Build the SQL string one time.*/
SET #SQLString = N'SELECT BusinessEntityID, NationalIDNumber, JobTitle, LoginID
FROM AdventureWorks2012.HumanResources.Employee
WHERE BusinessEntityID = #BusinessEntityID';
SET #ParmDefinition = N'#BusinessEntityID tinyint';
/* Execute the string with the first parameter value. */
SET #IntVariable = 197;
EXECUTE sp_executesql #SQLString, #ParmDefinition,
#BusinessEntityID = #IntVariable;
/* Execute the same string with the second parameter value. */
SET #IntVariable = 109;
EXECUTE sp_executesql #SQLString, #ParmDefinition,
#BusinessEntityID = #IntVariable;
For dynamic you have to pass something like this
EXECUTE sp_executesql N'Select * from Admin WHERE ID = #ID and FirstName=#FName',
N'#ID tinyint, #FName varchar(250)',
#ID = 2, #FName = 'admin';

Create table with instruction into #parameter in stored procedure

I want to create a table from this code in SQL Server, but the stored procedure returns an error
CREATE PROCEDURE Recovery_CountryCode (#NombreTabla SYSNAME)
AS
DECLARE #ParamDefinition nvarchar(500);
DECLARE #SQLString nvarchar (4000);
SET #SQLString=N'SELECT Name
INTO #TableName
FROM AdventureWorks2008R2.Production.Location';
SET #ParamDefinition=N'#TableName SYSNAME';
EXECUTE sp_executesql #SQLString, #ParamDefinition, #TableName=#NombreTabla;
GO
I want avoid define table
When I call the stored procedure:
EXEC Recovery_CountryCode #NombreTabla='Paises';
I get the follow message:
Mens. 102, Nivel 15, Estado 1, LĂ­nea 2
Sintaxis incorrecta cerca de '#TableName'.
You can just concatenate the SQL inside your procedure
CREATE PROCEDURE Recovery_CountryCode (#NombreTabla SYSNAME)
AS
DECLARE #ParamDefinition nvarchar(500);
DECLARE #SQLString nvarchar (4000);
SET #SQLString=N'SELECT Name INTO ' +
#NombreTabla +
' FROM AdventureWorks2008R2.Production.Location';
EXECUTE sp_executesql #SQLString
GO
You can't bind variables to table names in this way. You need to do something like
Declare #sql nvarchar(max), #NombreTable sysname = 'Test'
Set #sql = N'Select Name Into ' + #NombreTable +
N' From AdventureWorks2008R2.Production.Location
exec sp_executesql #sql
http://www.sommarskog.se/dynamic_sql.html is recommended reading.

How a store executed variable output into another variable, SQL

Here is my snippets:
create procedure sp (#pre nvarchar(50), #count nvarchar(50))
as
declare #preval nvarchar(500);
declare #countval nvarchar(500);
select #preval = 'select '+ #prefix + ' from tblc'
select #countval= 'select '+ #counter + ' from tblc'
exec sp_executesql #preval,#countval
pre and count are a 2 input parameters which has gives "columnsname1" and "columnname2" which are dynamic. I want to build a query/sp which gives me the value inside that particular columns and i want to store them in 2 different or single variable inside my sp. Til now I'm getting column name as result which I don't want, I want value inside the particular column.nd also want that value in a 3rd variable! If any doubt let me know.
Well... assuming that your example is pseudo code, and not expected to work verbatim, you could benefit from reading how sp_executesql works - noting that the second parameter is not a subsequent command to execute.
Having done that, you might try the following:
create procedure sp (#prefix nvarchar(50), #counter nvarchar(50))
as
declare #preval nvarchar(500);
declare #countval nvarchar(500);
select #preval = 'select '+ #prefix + ' from tblc'
select #countval= 'select '+ #counter + ' from tblc'
declare #cmd as nvarchar(500);
set #cmd = #preval+';'+#countval
exec sp_executesql #cmd
...and pray someone doesn't do this...
sp '1; delete',''
Personally, I would question why you feel the need to go down this road.
However, you will probably find that if you read up on sp_executesql, and look at the following example, you will find a way to get what you need. I'm guessing that the 'tblc' table only has a single row ?
declare #sql as nvarchar(4000)
declare #p1 as integer
set #sql = 'select #p1=count(*) from tblc'
exec sp_executesql #sql, N'#p1 int output', #p1 output
select #p1