Stored Procedure that has table argument in T-SQL - sql-server

Table Argument as OUTPUT
I want to pass a table variable into a procedure that has table argument as output,
but not as read only! I want to be able to modify that argument inside the PROC.
Is this possible?
If it's not possible, is there another way to do this?
thanks!

You'd have to copy the table valued parameter into a table variable or temp table
CREATE PROC DoStuff
#tvp SomeTableType READONLY
AS
..
SELECT * INTO #LocalCopy FROM #tvp; -- take local copy
...
DoStuff -- do processing on the input
...
SELECT ... FROM LocalCopy; --return results to client
GO
After comment, a table valued parameter can not be declared OUTPUT. From CREATE PROC
A table-value data type cannot be specified as an OUTPUT parameter of a procedure.

Related

Pass test data to table-valued parameter within SQL

Is it possible, and if so how, to pass data to a table-valued parameter of a stored function using SQL EXEC?
I know how to pass in data from C#. One of my four stored procs using table-valued parameters is not producing the expected results. I'd like to execute my proc from SQL server management studio for debugging purposes, but I am unable to find the correct syntax for doing so, if such a syntax even exists. I haven't found anything relevant in the docs.
My type table:
CREATE TYPE [MyNameSpace].[MyTypeTable] AS TABLE(
//... all my fields
)
My stored proc:
//... bunch of stuff
ALTER PROCEDURE [MyNameSpace].[MyStoredProc]
#MyTypeTableVar MyTypeTable READONLY
AS
BEGIN
//Do a bunch of stuff
//Want to test the stuff in here
END
I have tried:
IF OBJECT_ID('tempdb.dbo.#MyTempTable') IS NOT NULL DROP TABLE tempdb.dbo.#MyTempTable;
select top 0 *
into #MyTempTable
//existing table with structure that matches the table-valued param
from MyNameSpace.MyTable;
//...Long insert statement assigning test data to #MyTempTable
EXECUTE MyNameSpace.MyStoredProc #MyTypeTableVar = #MyTempTable;
which throws:
Operand type clash: nvarchar is incompatible with MyTypeTable
You can't use a temp table - you have to use a table variable:
declare #t [MyNameSpace].[MyTypeTable]
insert into #t (/*columns*/) values
(/* first row */),
(/* second row */)
EXECUTE MyNameSpace.MyStoredProc #MyTypeTableVar = #t;
(You can populate it with either INSERT ... VALUES as shown above or INSERT ... SELECT if you have an existing table containing the data you care about)
Here's a working example:
-- Declare a table parameter
DECLARE #registryUpdates AS typ_KeyValuePairStringTable;
-- Insert one row
INSERT INTO #registryUpdates
VALUES ('Hello', 'World');
-- Call Stored Procedure
EXEC prc_UpdateRegistry #registryUpdates

Define a table type parameter

I just try to create a table type parameter called "ListOfName", and set a parameter of such type in my procedure. But an error incurred:
Must declare the scalar variable "#Table_Name_List"
But I declare
CREATE TYPE ListOfName AS TABLE (Table_Name nvarchar(50) );
CREATE PROCEDURE spTest
#Table_Name_List ListOfName READONLY
AS
SELECT * from dbo.Table_Size_Daily
WHERE Table_NAME IN (#Table_Name_List)
Go
If I add a statement before the definition chunk,
DECLARE #Table_Name_List AS ListOfName;
The error was:
The variable name '#Table_Name_List' has already been declared.
Variable names must be unique within a query batch or stored
procedure.
How can I fix it? Thanks a lot
I can see that there is misconception on what a Table Type is. Even though there is only one column in your table type, you can't treat that as a single-column argument.
Consider a Table type parameter as any other table irrespective of
number of columns you have.
In order to fix your issue, I would prefer your WHERE condition to change as below:
WHERE Table_NAME IN (SELECT Table_Name FROM #Table_Name_List)
However, I would strongly recommend you to read a few tutorials on Table type before you proceed with any implementation. For ex: This Table Valued Parameters article on MSDN gives clear insight into it.

How to pass string array in 'In' clause in sql stored procedure

I have user table in database storing user information. I want to create stored procedure in which I will pass UserIDs as a list. I want to use this list to fetch data from user table.
I am creating type as a table using following query:
CREATE TYPE dbo.MyUserIDs AS TABLE (UserID int)
Now I am using this type in stored procedure:
ALTER PROCEDURE [dbo].[Test_in_Query]
#MyUserids MyUserIDs READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT * From Tbl_UserMast where UserID in (select UserID from #MyUserids)
END
When I execute this code I am getting following error:
Operand type clash: int is incompatible with MyUserIDs
I am following this link as a reference:
Reference link
I am directly executing stored procedure in sql server
I don't think you can pass a TVP-value using the SSMS gui (or at least I'm not aware of how to do it), but you have to do it in t-sql code, like so:
-- declare a variable using the user-defined type
DECLARE #MyUsers MyUserIDs
-- insert some data into it
INSERT INTO #MyUsers(UserID) VALUES (1),(2),(4)
-- and pass it into the proc
EXEC Test_in_Query #MyUserids = #MyUsers

Passing multiple value parameters in SSRS to stored procedure

I am trying to pass a multiple value string parameter to a table type parameter in a SQL Server 2012 stored procedure. I paste this code in the dataset of SSRS:
DECLARE #mylist clinic_list_tbltype
INSERT #mylist(n) VALUES (#pm_ChooseClinics)
EXEC sp_Skillset_Summary_With_Callbacks_Report #mylist, #pm_ChooseInterval, #pm_StartDateTime, #pm_EndDateTime
clinic_list_tbltype is a table type I created with one varchar(50) field named "n". I can call this stored procedure from SSMS o.k. like this (and it comes back very fast):
DECLARE #mylist clinic_list_tbltype
INSERT #mylist(n) VALUES ('clinicA'), ('clinicB')
EXEC sp_Skillset_Summary_With_Callbacks_Report #mylist, 'Daily', '6/3/2014', '6/9/2014'
I can run in SSRS for only one clinic (but very slow), but if I try more than one it gives an error saying that
there are fewer columns in the INSERT statement than values specified
in the Values clause
. Even running for one clnic it works, but it takes a very very long time compared to running the query in SSMS. Like 2 minutes vs. 1 second. Must be because I'm passing ('clinicA', 'clinicB') instead of ('clinicA'), ('clinicB').
How to do?
Right I need to give you some back ground 1st.
When you allow SSRS parameter to select multiple values, The selection of multiple values creates a comma deliminated string of value as one string
'value1,value2,value3'
To check values in a string using IN operator we need strings concatenated with commas something like this ....
'value1','value2','value3'
Your Proc
Now in your proc when you insert values explicitly it inserts multiple values into your table.
INSERT INTO Table_Value_Param
VALUES ('value1'), --<-- 1st value/Row
('value2'), --<-- 2nd Value/Row
('value3') --<-- 3rd Value/Row
and this gives you back the expected results as when inside your procedure you execute a statement like
SELECT *
FROM Table_Name
WHERE ColumnName IN (SELECT ColumnName
FROM Table_Value_Param)
On the other hand when you try to insert into table using SSRS report Parameter you table inserts value like
INSERT INTO Table_Value_Param
VALUES ('value1,value2,value3') --<-- One Row/Value containing all the values comma separated
Solution
Creating TVP in this situation doesnt really help, What I do is make use of dbo.Split() function inside my procedure.
You can find many definitions for split function online, for a some cool ones have a look here Split Function equivalent in tsql?
Once you have created this split function just use this function inside your procedure definition you dont even need the Table valued parameters then.
Something like this...
SELECT *
FROM Table_Name
WHERE ColumnName IN (
SELECT Value
FROM dbo.Split(#Report_Param, ',')
)
declare #Vendors_Filter nvarchar(max) = 'a,b,c'
declare #Vendors nvarchar(max)
set #Vendors =''''+replace(#Vendors_Filter,',',''',''')+''''
select #Vendors

How to return temporary table from stored procedure

CREATE PROCEDURE [test].[proc]
#ConfiguredContentId int,
#NumberOfGames int
AS
BEGIN
SET NOCOUNT ON
RETURN
#WunNumbers TABLE (WinNumb int)
INSERT INTO #WunNumbers (WinNumb)
SELECT TOP (#NumberOfGames) WinningNumber
FROM [Game].[Game] g
JOIN [Game].[RouletteResult] AS rr ON g.[Id] = rr.[gameId]
WHERE g.[ConfiguredContentId] = #ConfiguredContentId
ORDER BY g.[Stoptime] DESC
SELECT WinNumb, COUNT (WinNumb) AS "Count"
FROM #WunNumbers wn
GROUP BY wn.[WinNumb]
END
GO
This stored procedure returns values from first select statement, but I would like to have values from second select statement to be returned. Table #WunNumbers is a temporary table.
Any ideas???
Take a look at this code,
CREATE PROCEDURE Test
AS
DECLARE #tab table (no int, name varchar(30))
insert #tab select eno,ename from emp
select * from #tab
RETURN
What version of SQL Server are you using? In SQL Server 2008 you can use Table Parameters and Table Types.
An alternative approach is to return a table variable from a user defined function but I am not a big fan of this method.
You can find an example here
A temp table can be created in the caller and then populated from the called SP.
create table #GetValuesOutputTable(
...
);
exec GetValues; -- populates #GetValuesOutputTable
select * from #GetValuesOutputTable;
Some advantages of this approach over the "insert exec" is that it can be nested and that it can be used as input or output.
Some disadvantages are that the "argument" is not public, the table creation exists within each caller, and that the name of the table could collide with other temp objects. It helps when the temp table name closely matches the SP name and follows some convention.
Taking it a bit farther, for output only temp tables, the insert-exec approach and the temp table approach can be supported simultaneously by the called SP. This doesn't help too much for chaining SP's because the table still need to be defined in the caller but can help to simplify testing from the cmd line or when calling externally.
-- The "called" SP
declare
#returnAsSelect bit = 0;
if object_id('tempdb..#GetValuesOutputTable') is null
begin
set #returnAsSelect = 1;
create table #GetValuesOutputTable(
...
);
end
-- populate the table
if #returnAsSelect = 1
select * from #GetValuesOutputTable;
YES YOU CAN.
In your stored procedure, you fill the table #tbRetour.
At the very end of your stored procedure, you write:
SELECT * FROM #tbRetour
To execute the stored procedure, you write:
USE [...]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[getEnregistrementWithDetails]
#id_enregistrement_entete = '(guid)'
GO
The return type of a procedure is int.
You can also return result sets (as your code currently does) (okay, you can also send messages, which are strings)
Those are the only "returns" you can make. Whilst you can add table-valued parameters to a procedure (see BOL), they're input only.
Edit:
(Or as another poster mentioned, you could also use a Table Valued Function, rather than a procedure)
First create a real, permanent table as a template that has the required layout for the returned temporary table, using a naming convention that identifies it as a template and links it symbolically to the SP, eg tmp_SPName_Output. This table will never contain any data.
In the SP, use INSERT to load data into a temp table following the same naming convention, e.g. #SPName_Output which is assumed to exist. You can test for its existence and return an error if it does not.
Before calling the sp use this simple select to create the temp table:
SELECT TOP(0) * INTO #SPName_Output FROM tmp_SPName_Output;
EXEC SPName;
-- Now process records in #SPName_Output;
This has these distinct advantages:
The temp table is local to the current session, unlike ##, so will not clash with concurrent calls to the SP from
different sessions. It is also dropped automatically when out of scope.
The template table is maintained alongside the SP, so if changes are
made to the output (new columns added, for example) then pre-existing
callers of the SP do not break. The caller does not need to be changed.
You can define any number of output tables with different naming for
one SP and fill them all. You can also define alternative outputs
with different naming and have the SP check the existence of the temp
tables to see which need to be filled.
Similarly, if major changes are made but you want to keep backwards
compatibility, you can have a new template table and naming for the later
version but still support the earlier version by checking which temp
table the caller has created.

Resources