Getting query result into table variable - sql

So I have declared a query within a varchar variable like:
DECLARE #sql VARCHAR(MAX) = 'select * from table'
I've also declared a temp table #Results that matches the column structure of the query.
I then call:
INSERT INTO #Results
EXEC (#sql)
The error I get is:
An INSERT EXEC statement cannot be nested.
I would also like to add that the query executes fine without the part
INSERT INTO #Results
What could be causing it? Any tips will be greatly appreciated

You can't stack together more than 1 INSERT INTO + EXEC, this is a limitation from SQL Server.
DECLARE #Test TABLE (Number INT)
INSERT INTO #Test (Number)
EXEC ('
CREATE TABLE #InnerTable (SomeColumn INT);
INSERT INTO #InnerTable (SomeColumn)
EXEC (''SELECT 1'');
SELECT 1;')
Msg 8164, Level 16, State 1, Line 4 An INSERT EXEC statement cannot be
nested.
If we remove the inner INSERT INTO + EXEC...
DECLARE #Test TABLE (Number INT)
INSERT INTO #Test (Number)
EXEC ('
CREATE TABLE #InnerTable (SomeColumn INT);
SELECT 1;')
Succeed!
There are multiple ways to workaround this limitation, however most of them will require modifying the EXEC content. You can find an exhaustive explanation here. The one I usually use with my procedures is sharing a temporary table. You need to create a temporary table outside the EXEC then load it inside. The table is still accessible outside the EXEC scope because it was created outside.
IF OBJECT_ID('tempdb..#Test') IS NOT NULL
DROP TABLE #Test
CREATE TABLE #Test (Number INT)
EXEC ('INSERT INTO #Test (Number) SELECT 1')
SELECT * FROM #Test
Downside of this approach is that the EXEC part might fail if the temporary table wasn't created or it was created with wrong column names or data types. Keep in mind that this won't work with variable tables, they need to be temporary (at least) to be accessible inside the EXEC scope.

Related

Inserting into a user-defined table type via a dynamic query in SQL Server?

I have a user-defined table type tyAnalysisNumbers. I need to populate my user defined data type within a stored procedure with a SELECT statement and I am struggling to get that working within my stored procedure.
The following ways I have tried do not work
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM ' + #someTable);
I get this error:
An INSERT EXEC statement cannot be nested
I am unsure how to insert into my custom table via a select statement.
Can anyone help me accomplish this?
An INSERT EXEC statement cannot be nested
Above error is self explanatory. Please look at below scenario:
For example, we have one procedure which inserts data in table type and return result.
CREATE PROCEDURE uspInsertData1
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM someTable');
select * from #MyTable
END
Now, let's say we have another procedure which will call above procedure and again insert data in another table.
CREATE PROCEDURE uspInsertData2
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO sometable
EXEC uspInsertData1
END
Now, if you execute 1st procedure it will work fine but if you execute second procedure you will get this error.
An INSERT EXEC statement cannot be nested.
Because now you have nested EXEC statements.
I suggest to finish your work in single stored procedure if possible.
Try it like this:
DECLARE #MyTable tyAnalysisNumbers;
SELECT * INTO #Temp FROM #MyTable;
DECLARE #tblName AS SYSNAME = (SELECT name FROM sys.tables WHERE name = #someTable);
EXEC ('INSERT INTO #Temp SELECT * FROM ' + #tblName);
This also addresses the SQL Injection problem.

Select * into #Temp not working in dynamic SQL

When I create a temporary table and insert data into that temporary table through dynamic SQL its work fine. But when I use select * into #TempTable1 from YourTable in dynamic SQL it throw error. I am unable to understand the cause of this error.
Table:
create table YourTable(Id int identity(1,1),Col1 varchar(100));
insert into YourTable(Col1)
values('Stack'),('Over'),('Flow')
Working Code:-
Declare #SqlStr varchar(max)
create table #TempTable(Id int identity(1,1),Col1 varchar(100))
set #SqlStr='Insert into #TempTable(Col1) select Col1 from YourTable'
exec(#SqlStr)
select * from #TempTable
Not Working Code:
Declare #SqlStr varchar(max)
set #SqlStr='select * into #TempTable1 from YourTable'
exec(#SqlStr)
select * from #TempTable1
Error:
Msg 208 Level 16 State 0 Line 4
Invalid object name '#TempTable1'.
For Reference data is here.
The cause of this error is that a temp table is session bound and your dynamic SQL runs in a separate session.
Use a global temp table (prefix: ##) and make this one unique by naming (i.e. add a guid to the name). This way the dynamic SQL can see it.
Different types temporary tables: http://www.sqlines.com/articles/sql-server/local_and_global_temporary_tables

Insert result of EXEC into table parameter

In a stored procedure, I have an EXEC statement; I want to store its results into a table.
First I create table parameter as:
DECLARE #MyTable AS TABLE
(
[Item1] INT,
[Item2] DECIMAL
)
Then I try to insert values as:
INSERT INTO #MyTable
EXEC [storedProcedure] #testitem = #testitem
My question: is this the right way to do that? Or do I need to use a dynamic query?
Because I read similar questions like this and they suggest to use a dynamic query.
You have to use a dynamic query.
DECLARE #Sql AS VARCHAR(MAX);
SET #Sql='EXEC storedProcedure #testitem = #testitem'
INSERT INTO #MyTable ([Item1], [Item2]) EXEC(#Sql)
SELECT * FROM #MyTable;
Asserting the above, I've been just tempted to read further... and found this older thread. I bet, it is helpful to analyze it further. Insert results of a stored procedure into a temporary table

T-SQL - Easier way to use stored procedure data

I have a bunch of stored procedures that I call all of the time. I can't change the procedures themselves due to another program that makes use of them. Most of them do NOT have outputs, but have something like this to return value:
SELECT Duration = dbo.fn_Duration(#intPD, #dtmStart, dtmEnd, null)
Currently I am taking every stored procedure and returning it into a table like this:
CREATE TABLE #ResultTable(ret float)
INSERT INTO #ResultTable
EXEC sp_Duration #ID
SELECT #Duration = ret
FROM #ResultTable
Now - because I have 13 stored procedures, I'm doing this over and over (as well as running a delete from #ResultTable) and then pushing this to a table as sort of a "roll up" of data. The purpose is to have 1 location reading the data at a specified interval instead of running the stored procedures over and over from multiple web pages.
I would like to do it more briefly than I am doing it (which is approximately 4 lines of code for each stored procedure. I was hoping to do it more like this:
INSERT INTO #FullResultsTable
EXEC sp_Duration #ID, EXEC sp_GetID #Name, ......
However - that does not seem possible :(
Any ideas on how I can do this better WITHOUT changing the stored procedures themselves?
You cant nest INSERT EXEC commands e.g.
INSERT INTO #Table
EXEC procedure1
EXEC procedure2
would just run the first on in the insert and then run the second as a stand alone command, likewise
INSERT INTO #Table
EXEC procedure1
UNION
EXEC procedure2
would error on the UNION
If you want all the data in one table then you can run multi INSERT INTO EXEC commands to populate the same table. e.g.
CREATE PROCEDURE #TEST1 AS
(
SELECT 1
)
GO
CREATE PROCEDURE #TEST2 AS
(
SELECT 1
)
GO
CREATE PROCEDURE #TEST3 AS
(
SELECT 1
)
GO
CREATE TABLE #TESTTABLE (ID INT)
INSERT INTO #TESTTABLE
EXEC #TEST1
INSERT INTO #TESTTABLE
EXEC #TEST2
INSERT INTO #TESTTABLE
EXEC #TEST3
SELECT * FROM #TESTTABLE
DROP PROCEDURE #TEST1
DROP PROCEDURE #TEST2
DROP PROCEDURE #TEST3
DROP TABLE #TESTTABLE
This would return the results:
ID
1
1
1

How to use parameters in sql queries (sp_executesql not working as per requirement)

I have used temporary tables plus temporary variables..
Now when my sql queries are having both temporary variables and table, i got to know sp_executesql not working because we can't use temporary tables in it
and standard execution won't take the variable parameters.
So it will be very helpfull if anyone can help me out with some other solution for it?
This is a sample code :
create procedure tryit
as begin
declare #temp as Table_Type;
declare #ghdhj as nvarchar(50)
set #ghdhj='TBVHTempSelectionTable';
declare #sqlstatement nvarchar(max);
set #sqlstatement=N'insert into #temp select * from '+#ghdhj+';';
exec sp_executesql #sqlstatement;
--,#temp='finalResultTable',#ghdhj='TBVHTempSelectionTable'
select * from #temp;
end
go
exec tryit
Create temporary table and then execute sp_executesql
If you create the temporary table first you should be able to access it in sp_executesql if you specify it explicitly
select *
into #peter
from (values (10), (10)) p(a);
exec sp_executesql N'insert into tempdb..#peter values (20), (20)';
select * from #peter;
-- Result
A
10
10
20
20
sp_executesql can accept table valued parameters, so you can pass a table variable to sp_executesql.
First, you need a table type defined on your database. You create table types using CREATE TYPE statement. For example:
CREATE TYPE dbo.CategoryTableType AS TABLE
(
CategoryID int,
CategoryName nvarchar(50)
)
GO
Once you have the table type you can pass table variables of that type to sp_executesql. For example:
DECLARE #Categories CategoryTableType
INSERT INTO #Categories
VALUES (1, 'Beverages'), (2, 'Confections')
EXEC dbo.sp_executesql
N'SELECT * FROM #Categories',
N'#Categories CategoryTableType READONLY',
#Categories
sp_executesql cannot access variables of any kind declared outside the sql statement passed to sp_executesql.
However sp_executesql can access to temporary tables created in the calling scope stack. For example:
CREATE TABLE #Categories (
CategoryID int,
CategoryName nvarchar(50)
)
INSERT INTO #Categories VALUES
(1, 'Beverages'), (2, 'Confections')
EXEC dbo.sp_executesql N'SELECT * FROM #Categories'
DROP TABLE #Categories
On the other hand the calling scope cannot access to temporary tables created in the sql statement passed to sp_executesql. For example the following code will fail with Msg 208, Level 16, State 0, Invalid object name '#Categories'.
EXEC dbo.sp_executesql N'
CREATE TABLE #Categories (
CategoryID int,
CategoryName nvarchar(50)
)
INSERT INTO #Categories VALUES
(1, ''Beverages''), (2, ''Confections'')'
SELECT * FROM #Categories
Also, the calling scope cannot access to any variable declared inside the sql statement passed to sp_executesql