sp_executesql and table output - sql

I'm writing a stored procedure in SQL Server 2005, at given point I need to execute another stored procedure. This invocation is dynamic, and so i've used sp_executesql command as usual:
DECLARE #DBName varchar(255)
DECLARE #q varchar(max)
DECLARE #tempTable table(myParam1 int, -- other params)
SET #DBName = 'my_db_name'
SET q = 'insert into #tempTable exec ['+#DBName+'].[dbo].[my_procedure]'
EXEC sp_executesql #q, '#tempTable table OUTPUT', #tempTable OUTPUT
SELECT * FROM #tempTable
But I get this error:
Must declare the scalar variable "#tempTable".
As you can see that variable is declared. I've read the documentation and seems that only parameters allowed are text, ntext and image. How can I have what I need?
PS: I've found many tips for 2008 and further version, any for 2005.

Resolved, thanks to all for tips:
DECLARE #DBName varchar(255)
DECLARE #q varchar(max)
CREATE table #tempTable(myParam1 int, -- other params)
SET #DBName = 'my_db_name'
SET #q = 'insert into #tempTable exec ['+#DBName+'].[dbo].[my_procedure]'
EXEC(#q)
SELECT * FROM #tempTable
drop table #tempTable

SQL Server 2005 allows to use INSERT INTO EXEC operation (https://learn.microsoft.com/en-us/sql/t-sql/statements/insert-transact-sql?view=sqlallproducts-allversions).
You might create a table valued variable and insert result of stored procedure into this table:
DECLARE #tempTable table(myParam1 int, myParam2 int);
DECLARE #statement nvarchar(max) = 'SELECT 1,2';
INSERT INTO #tempTable EXEC sp_executesql #statement;
SELECT * FROM #tempTable;
Result:
myParam1 myParam2
----------- -----------
1 2
or you can use any other your own stored procedure:
DECLARE #tempTable table(myParam1 int, myParam2 int);
INSERT INTO #tempTable EXEC [dbo].[my_procedure];
SELECT * FROM #tempTable;

#tempTable's scope is limited to the current procedure.
You could replace the #tempTable with a global temporary table (i.e. ## table), but be very careful with the scope of that table and be sure to drop it when the procedure ends

Related

T-SQL Execute from a stored procedure

I am trying to build an SQL inside a stored procedure and execute it using
EXEC sp_executesql
Now I defined a local table and tried to pass it in need to pass it in
CREATE TYPE mytabletypeAS TABLE (
StartDate DATETIME,
EndDate DATETIME,
Amount MONEY,
AccountId INT
);
The following happens in my stored procedure, what I am trying to do is to return the output produced by EXEC sp_executesql:
CREATE PROCEDURE attributevalues.sp_EvalClearingNetSpend
AS
BEGIN
DECLARE #OutPutTable AS mytabletype;
DECLARE #Sql AS NVARCHAR(MAX);
SET #Sql = 'INSERT INTO #OutPutTable SELECT StartDate,EndDate,Amount, AccountId FROM table1';
EXEC sp_executesql #Sql, N'#OutPutTable mytabletype OUTPUT', #OutPutTable OUTPUT;
SELECT * FROM #OutPutTable
END
The above is saying I cannot pass in OUTPUT with #OutPutTable
Help!!!
all i need to know is, is there a way I can get the values from a statement executed via EXEC and return it from my SP
Yes. But you can't do it with a table variable. You can pass a table variable into the nested batch with sp_executesql just like you pass one to a stored procedure, but it has to be marked readonly, and so you can't modify it.
You can see and modify existing temporary tables in nested batches, eg
drop table if exists table1
go
create table table1
(
StartDate DATETIME,
EndDate DATETIME,
Amount MONEY,
AccountId INT
)
insert into table1 values (getdate(),getdate(),1,1)
go
CREATE OR ALTER PROCEDURE EvalClearingNetSpend
AS
BEGIN
create table #t(
StartDate DATETIME,
EndDate DATETIME,
Amount MONEY,
AccountId INT)
Declare #Sql as NVARCHAR(MAX);
SET #Sql = 'INSERT INTO #T SELECT StartDate,EndDate,Amount, AccountId FROM table1';
EXEC sp_executesql #Sql
SELECT * FROM #T
END
go
exec EvalClearingNetSpend
outputs
StartDate EndDate Amount AccountId
----------------------- ----------------------- --------------------- -----------
2021-03-30 08:48:32.350 2021-03-30 08:48:32.350 1.00 1
This is an XY Problem. There is no need for the level of complexity you have put in the procedure. The table TYPE, the call to sys.sp_executesql, none of it is needed. Just put the SELECT statement of your "dynamic" query (it's not dynamic, as there's no object injection) in your Procedure:
CREATE PROCEDURE attributevalues.EvalClearingNetSpend AS --Removed sp_ prefix
BEGIN
SELECT StartDate,EndDate,Amount, AccountId FROM table1;
END;
GO
This completely avoids the error, that you are trying to use a table TYPE as an OUTPUT parameter, because you can't, but you don't need one here.
Not sure why you would go through the trouble of creating a Table Type parameter and populating it inside your from and then selecting from it. But lets say you do have to do this for some reason.
You can achieve this by doing this, no need to use output parameters at all, output parameter is used to return a scalar value, here you are getting a table back and then selecting from it:
CREATE PROCEDURE usp_EvalClearingNetSpend
AS
BEGIN
Declare #Sql as NVARCHAR(MAX);
SET #Sql = N' DECLARE #OutPutTable AS mytabletype;
INSERT INTO #OutPutTable
SELECT StartDate,EndDate,Amount, AccountId
FROM table1;
SELECT * FROM #OutPutTable
';
EXEC sp_executesql #Sql
END

SQL Server Linked Server INSERT INTO

I have problem with linked server at store procedure, I want to get data from linked server then insert into table.
This is my stored procedure:
CREATE PROCEDURE [dbo].[SP_GETPRODRECORD]
#PR_NO varchar(10)=''
AS
BEGIN
DECLARE #OPENQUERY nvarchar(4000),
#TSQL nvarchar(4000),
#LinkedServer nvarchar(4000)
CREATE TABLE AAA (PR varchar(10))
SET #LinkedServer = 'LS'
SET #OPENQUERY = 'INSERT INTO AAA SELECT * FROM OPENQUERY('+ #LinkedServer + ','''
SET #TSQL = 'SELECT PSHN9G FROM F9G00 WHERE PSHN9G='''''+#PR_NO+''''')'
EXEC (#OPENQUERY+#TSQL)
END
My problem is that the EXEC is not running, when I try to insert manually with code below is working
INSERT INTO AAA(PR)
SELECT PSHN9G
FROM OPENQUERY(WAVEDLIB,'SELECT PSHN9G FROM F9G00 WHERE PSHN9G=''XXXXXXX'')
Am I missing something?
Thanks
There is no need to use OPENQUERY and EXECUTE, you can simply reference LinkedServer if you know which DB is your table into:
CREATE PROCEDURE [dbo].[SP_GETPRODRECORD]
#PR_NO varchar(10)=''
AS
BEGIN
--No need to CREATE TABLE every time you exec SP. SELECT INTO #temp table instead.
SELECT PSHN9G INTO #temp FROM WAVEDLIB.DBName.dbo.F9G00 WHERE PSHN9G=#PR_NO
SELECT * FROM #temp
END

Stored procedure with a parameter in FROM clause

Is it possible to create a stored procedure that uses a parameter in the FROM clause?
For example:
CREATE PROCEDURE [dbo].[GetMaxId]
#id varchar(50)
#table varchar(50)
AS
BEGIN
SELECT MAX(#id)
FROM #table
END
You cannot pass identifiers as parameters into a query (neither table names nor column names). The solution is to use dynamic SQL. Your syntax suggests SQL Server, so this would look like:
CREATE PROCEDURE [dbo].[GetMaxId] (
#id varchar(50)
#table varchar(50)
)
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT MAX(#id) FROM #table';
SET #sql = REPLACE(REPLACE(#sql, '#id', QUOTENAME(#id)), '#table', QUOTENAME(#table));
EXEC sp_executesql #sql;
END; -- GetMaxId

Pass temp table to EXEC sp_executesql

How can I pass temp table (#table) to EXEC sp_executesql #query
set #query = 'SELECT GsName, ' + #cols + ' from
(
select GSName, [THour], NumOfTransactions
from #table
) x
pivot
(
max([NumOfTransactions])
for [THour] in (' + #cols + ')
) p '
What you have here is not Temporary Table, but a Table-Valued Parameter.
Table-valued parameters are declared by using user-defined table
types. You can use table-valued parameters to send multiple rows of
data to a Transact-SQL statement or a routine, such as a stored
procedure or function, without creating a temporary table or many
parameters.
sp_executesql does support table-valued parameters, but they must be of declared type.
-- So, first we must declare User-Defined Table Type
CREATE TYPE udtYB_Test AS TABLE(GSName nvarchar(100), THour time, NumOfTransactions int);
GO
-- Now we can create Table-Valued Parameter
Declare #table udtYB_Test;
-- And store there some data
Insert Into #table (GSName, THour, NumOfTransactions)
Values ('Sample', SYSUTCDATETIME(), 1);
-- Just for the reference
Select * From #table;
-- To pass variable to sp_executesql we need parameters definition
DECLARE #ParmDefinition nvarchar(500) = N'#table udtYB_Test READONLY';
-- Please note: table-valued parameter must be READONLY
-- Here I use simplified query for demonstration only
DECLARE #query nvarchar(500) = 'SELECT * FROM #table';
-- and the result should be identical to the reference above
EXECUTE sp_executesql #query, #ParmDefinition, #table = #table;
-- User-Defined Table Type cleanup
DROP TYPE udtYB_Test;
GO
In most practical cases it is much easier to use a temporary table:
Create Table #table (GSName nvarchar(100), THour time, NumOfTransactions int);
Insert Into #table (GSName, THour, NumOfTransactions) Values ('Sample', SYSUTCDATETIME(), 1);
Select * From #table;
DECLARE #query nvarchar(500) = 'SELECT * FROM #table';
EXECUTE sp_executesql #query;
Drop Table #table;

Pass a TABLE variable to sp_executesql

I'm trying to pass a TABLE variable to the sp_executesql procedure:
DECLARE #params NVARCHAR(MAX)
SET #params = '#workingData TABLE ( col1 VARCHAR(20),
col2 VARCHAR(50) )'
EXEC sp_executesql #sql, #params, #workingData
I get the error:
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'TABLE'.
I tried omitting the column specification after 'TABLE'. I also tried to declare the table as a variable inside the dynamic SQL. But no luck...
Seems to me that TABLE variables aren't allowed to be passed as parameters in this procedure?. BTW: I'm running MSSQL2008 R2.
I'm not interested in using a local temp table like #workingData because I load the working data from another procedure:
INSERT INTO #workingData
EXEC myProc #param1, #param2
Which I cannot do directly into a temp varaible (right?)...
Any help appreciated!
If you are using SQL Server 2008, to pass a table variable to a stored procedure you must first define the table type, e.g.:
CREATE TYPE SalesHistoryTableType AS TABLE
(
[Product] [varchar](10) NULL,
[SaleDate] [datetime] NULL,
[SalePrice] [money] NULL
)
GO
or use an existing table type stored in the database.
Use this query to locate existing table types
SELECT * FROM sys.table_types
To use in an stored procedure, declare an input variable to be the table:
CREATE PROCEDURE usp_myproc
(
#TableVariable SalesHistoryTableType READONLY
)
AS BEGIN
--Do stuff
END
GO
Populate the table variable before passing to the stored procedure:
DECLARE #DataTable AS SalesHistoryTableType
INSERT INTO #DataTable
SELECT * FROM (Some data)
Call the stored procedure:
EXECUTE usp_myproc
#TableVariable = #DataTable
Further discussions here.
OK, this will get me what I want, but surely isn't pretty:
DECLARE #workingData TABLE ( col1 VARCHAR(20),
col2 VARCHAR(20) )
INSERT INTO #workingData
EXEC myProc
/* Unfortunately table variables are outside scope
for the dynamic SQL later run. We copy the
table to a temp table.
The table variable is needed to extract data directly
from the strored procedure call above...
*/
SELECT *
INTO #workingData
FROM #workingData
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT * FROM #workingData'
EXEC sp_executesql #sql
There must be a better way to pass this temporary resultset into sp_executesql!?
Regards
Alex
While this may not directly answer your question, it should solve your issue overall.
You can indeed capture the results of a Stored Procedure execution into a temporary table:
INSERT INTO #workingData
EXEC myProc
So change your code to look like the following:
CREATE TABLE #workingData ( col1 VARCHAR(20),
col2 VARCHAR(20) )
INSERT INTO #workingData
EXEC myProc
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT * FROM #workingData'
EXEC sp_executesql #sql
Regards,
Tim
Alter PROCEDURE sp_table_getcount
#tblname nvarchar(50) ,
#totalrow int output
AS
BEGIN
Declare #params nvarchar(1000)
Declare #sql nvarchar(1000)
set #sql = N'Select #cnt= count(*) From #tbl'
set #params = N'#tbl nvarchar(50) , #cnt int OUTPUT'
Exec sp_executesql #sql , #params ,#tbl=#tblname , #cnt = #totalrow OUTPUT
END
GO
Please note that the above code will not work as table as a object is out of the scope.It will give you the error: must declare table variable.In order to work around we can do the following.
Alter PROCEDURE sp_table_getcount
#tblname nvarchar(50) ,
#totalrow int output
AS
BEGIN
Declare #params nvarchar(1000)
Declare #sql nvarchar(1000)
set #sql = N'Select #cnt= count(*) From dbo.' + #tblname
set #params = N'#cnt int OUTPUT'
Exec sp_executesql #sql , #params , #cnt = #totalrow OUTPUT
END
GO
So-called TableType is tricky. #Alex version should work. However, to simplify and faster performance, go check sys.tables for matching table name while not compromise security and performance.
Here it is
create proc [dbo].Test11
#t1 AS nvarchar(250), #t2 nvarchar(250)
AS
BEGIN
SET nocount ON;
DECLARE #query AS nvarchar(MAX)
if exists (select * from sys.tables where name = #t1) and
exists (select * from sys.tables where name = #t2)
begin
SET #query = N'select * FROM '+ #t1 + N' join ' + #t2 + N' ON ...' ;
select 'Safe and fast'
print #query
exec sp_executesql #query
end
else
select 'Bad, no way Jose.'
SET nocount OFF;
END
GO