Get Current Sp parameters and values - (reflection alike)? - sql-server

Lets say I have this simple SP :
CREATE PROCEDURE mySp
#a int,
#b int
AS
BEGIN
...
...
select ________
END
Now let's say I execute it via :
exec mySp 1,2
Question :
Is there any code which I can place in the ______ so it will show me :
"you sent param named a with value 1"
"you sent param named b with value 2"
This code should be dynamic (pasted in some SP's). Hence I can't do :
select "you sent param named a...with value "+cast (#a...)
select "you sent param named b...with value "+cast (#b...)
(it has to read its context parameters and values at runtime)
Is it possible ?

I don't think it is possible to do it cleanly. One really dirty way of doing is to pass in an additional varchar column which is a comma separated list values of rest of the parameters. Then you can get the names of individual params and match them with the passed in parameter. Here's a sample
CREATE PROCEDURE mySp
#a int,
#b INT,
#c varchar(MAX)
AS
BEGIN
declare #names varchar(MAX) = ''
SELECT #names += name +','
FROM sys.parameters
WHERE object_id = ##PROCID AND name <> '#c'
ORDER BY parameter_id
SELECT 'The passed in values for '+#names + ' are ' +#c
END
go
EXEC mySp 1,1, '1,1'

Related

Need to mix dynamic SQL, Open Query, JSON, dynamic variables, and a few other oddities into a single query

Need to run dynamic SQL against DB2 on MS SQL through OpenQuery, get results back in JSON, then return this as an Output Parameter in a Stored Procedure
I've tried using a table variable as the sample code shows, but I get this error:
The FOR JSON clause is not allowed in a INSERT statement
I've also tried wrapping the query into a CTE, but given the JSON column name changes I can't use * or I get this error:
No column name was specified for column 1 of 'tbl'.
So I'm at a loss. I need to run this and get the JSON in the Output parameter, but given I'm having to mix a call to DB2 through OpenQuery and dynamic SQL to set the parameter I can't find a syntax that works.
create procedure uspTesting (
#inAccountNumber nvarchar(20),
#outJSON nvarchar(max) output)
as
begin declare #result table (ResultJson nvarchar(max));
declare #tsql nvarchar(4000) = '
select name, age
from openquery(db2link,''
select name,
age
from db2.account
where accountnumber = ''''' + #inAccountNumber + ''''')'') tbl for json auto';
insert into #result
EXEC (#TSQL);
select #outJSON = ResultJson from #result; End
The results I'm looking for are the JSON string in the output parameter #outJSON.
Apply the FOR JSON after you've gotten the data, load it into a temp table and then use the FOR JSON.
Without test data, etc you might have to adjust this, but try something like:
CREATE PROCEDURE [uspTesting]
(
#inAccountNumber NVARCHAR(20)
, #outJSON NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
DECLARE #result TABLE
(
[name] NVARCHAR(100) --whatever data type you need here
, [age] NVARCHAR(100)
);
DECLARE #tsql NVARCHAR(4000) = '
select name, age
from openquery(db2link,''
select name,
age
from db2.account
where accountnumber = ''' + #inAccountNumber + ''')';
--Here we will just load a table variable with the data.
INSERT INTO #result
EXEC ( #tsql );
--Then we will select from that table variable applying the JSON here.
SET #outJSON = (
SELECT *
FROM #result
FOR JSON AUTO
);
END;

SQL Server: get column value from string column name, assign value to variable

In SQL Server in a stored procedure, I want to get the value in a column of a single-row table given the column name, and assign that value to a variable. The column name may be different every time (I use T-SQL to interrogate the schema at run time).
The example given below is as minimal as I can make it, the important thing is that you cannot assume that the column name will always be entity_client, it could be anything at all, though (due to interrogation of INFORMATION SCHEMA) we will have the value assigned to the variable #entity_column_name.
Example preparation SQL:
IF OBJECT_ID('tempdb..#foo') IS NOT NULL
BEGIN;
DROP TABLE #foo;
END;
CREATE TABLE #foo
(
id INT,
entity_client NVARCHAR(255)
);
INSERT INTO #foo VALUES (1, 'clientcode|client_number');
DECLARE #entity_column_name NVARCHAR(255) = 'entity_client';
DECLARE #entity_column_value NVARCHAR(255);
I have tried the following:
SELECT TOP 1 #entity_column_name = [#entity_column_value]
FROM #foo;
...which generates an error
Invalid column name '#entity_column_value'
I have also tried:
EXEC('SELECT TOP 1 #entity_column_value = [' + #entity_column_name + '] FROM #foo;');
which generates another error
Must declare the scalar variable "#entity_column_value"
The following works, but unfortunately the column name is hard-coded - I wanted to be able to vary the column name:
SELECT TOP 1 #entity_column_value = [entity_client]
FROM #foo;
Yes, I have looked on SO and found the following questions, but they do not provide an answer where the value is assigned to a variable, in both cases the SELECT output is simply dumped to screen:
Get column value from string column name sql
Get column value from dynamically achieved column name
This will actually work but you need to declare the output variable:
DECLARE #entity_column_name NVARCHAR(255) = 'entity_client';
DECLARE #entity_column_value NVARCHAR(255);
DECLARE #tsql NVARCHAR(1000) = 'SELECT TOP 1 #entity_column_value = [' + #entity_column_name + '] FROM #foo;'
EXEC sp_executesql #tsql, N'#entity_column_value NVARCHAR(255) OUTPUT',
#entity_column_value OUTPUT;

T-SQL stored procedure - Detecting if a parameter is supplied as OUTPUT

Consider the following T-SQL code snippet:
CREATE PROC dbo.SquareNum(#i INT OUTPUT)
AS
BEGIN
SET #i = #i * #i
--SELECT #i
END
GO
DECLARE #a INT = 3, #b INT = 5
EXEC dbo.SquareNum #a OUTPUT
EXEC dbo.SquareNum #b
SELECT #a AS ASQUARE, #b AS BSQUARE
GO
DROP PROC dbo.SquareNum
The result set is:
ASQUARE BSQUARE
----------- -----------
9 5
As can be seen, #b is not squared, b/c it was not passed-in as output parameter (no OUTPUT qualifier when passing in the parameter).
I would like to know if there is a way I could check within stored procedure body (dbo.SquareNum body in this case) to see if a parameter has indeed been passed in as an OUTPUT parameter?
------ THIS WILL GIVE YOU THE BOTH VALUE IN squared------
CREATE PROC dbo.SquareNum(#i INT OUTPUT)
AS
BEGIN
SET #i = #i * #i
--SELECT #i
END
GO
DECLARE #a INT = 3, #b INT = 5
EXEC dbo.SquareNum #a OUTPUT
EXEC dbo.SquareNum #b OUTPUT
SELECT #a AS ASQUARE, #b AS BSQUARE
GO
DROP PROC dbo.SquareNum
-----TO CHECK STORED PROCEDURE BODY-----
SELECT OBJECT_NAME(object_id),
OBJECT_DEFINITION(object_id)
FROM sys.procedures
WHERE OBJECT_DEFINITION(object_id) =(SP_NAME)
Actually, there is a very simple way!
Make the parameter optional by setting a default value (#Qty AS Money = 0 Below)
Then, pass a value OTHER THAN THE DEFAULT when calling the procedure. Then immediately test the value and if it is other than the default value you know the variable has been passed.
Create Procedure MyProcedure(#PN AS NVarchar(50), #Rev AS NVarchar(5), #Qty AS Money = 0 OUTPUT) AS BEGIN
DECLARE #QtyPassed AS Bit = 0
IF #Qty <> 0 SET #QtyPassed = 1
Of course that means the variable cannot be used for anything other than OUTPUT unless you have a default value that you know will never be used as an INPUT value.
You can do this by query to sys views:
select
p.name as proc_name,
par.name as parameter_name,
par.is_output
from sys.procedures p
inner join sys.parameters par on par.object_id=p.object_id
where p.name = 'SquareNum'
or check in Management Studio in database tree:
[database] -> Programmability -> Stored Procedures -> [procedure] -> Parameters
Maybe I'm wrong but I don't believe it's possible. OUTPUT is part of the stored procedure definition so you should know when a parameter is or not OUTPUT. There is no way to set it dynamically so I think it's pointless to determine by code when a parameter is output or not because you already know it.
If you are trying to write a dynamic code, Piotr Lasota's answer should drive you to the correct way to realize when a parameter is Output.
Use the following query to get the name of all the parameters and to check if it is a output parameter:
select name, is_output from sys.parameters

Setting a variable to a certain value or default to all values in a column

Sorry if my heading is very clear. I am trying to create a stored procedure :
Create Procedure Pro1 #a nvarchar = null, #b nvarchar =null
as
Select * from table1
where Parameter1 = '1'
and Parameter2 = #a
go
Above is not the actual code but i hope it explains what i am trying to achieve. I am selecting on two parameters. 'Parameter2' depends on the variable #a. The challenge i have is that if #a remains null at execution; i want the select statement to search on all values of Parmeter2 as if the 'and' statement was not there. I could write a if else statement to execute different selects but i was hoping i could simply set #a to some sort
of wildcard value that would simply do this? Maybe something : 'like []'?
CREATE PROCEDURE dbo.Pro1 -- use schema prefix when creating objects!
#a NVARCHAR(32) = NULL -- 32 should match data type of Parameter2 column
AS
BEGIN -- wrap your body and indent for readability
SET NOCOUNT ON; -- should always turn off DONE_IN_PROC messages
SELECT columns -- please name your columns instead of SELECT *
FROM dbo.table1 -- use schema prefix when referencing objects
WHERE (Parameter2 = #a OR #a IS NULL); -- semi-colons please!
END
GO
In some cases you may find that if you have a lot of these optional parameters, SQL Server will compile a plan for one set of parameters and that plan will not be very beneficial for different parameters. So you may want something like this:
CREATE PROCEDURE dbo.Pro1
#a NVARCHAR(32) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT columns FROM dbo.table1 WHERE 1=1';
IF #a IS NOT NULL
SET #sql += ' AND Parameter2 = #a';
EXEC sp_executesql #sql,
N'#a NVARCHAR(32)',
#a;
END
GO

'Where in' T-SQL implementation

I have a stored procedure that take many input parameters including an #userID.
Now, in the core of the SP I select from a view using the following Where close :
Where userID = #userID
This works fine. Now I want to pass multiple users to be able wo query it like this :
where userID in (1,2,...)
How can I pass the value 1,2 from one input parameter ?
Thanks
Create a function split:
create FUNCTION [dbo].[Split]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(2000)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
--select Value from dbo.Split('item1, item2, item3',',')
END
GO
And call the function with #PASS and use it inside a cursor.
Arrays and Lists in SQL Server
Create an input parameter which is a table varaible and send in the array as a table that you join to instead of using in. Read about this in BOL as it can be a little tricky to set up.

Resources