Insert dynamic query results into un-defined temp table? - sql

I'm defining a long dynamic query and I'd like to insert it's results into a table. However, I'd prefer not to define the table first. Is this possible?
The query works correctly, I see the expected results if I run this:
declare #query VARCHAR(MAX)
#query = 'SELECT
--a bunch of stuff involving joins and pivots and such
'
execute (#query)
But neither of these attempts to select into an un-defined temp table work:
--attempt 1
declare #query VARCHAR(MAX)
#query = 'SELECT * INTO #T1 (
SELECT
--a bunch of stuff involving joins and pivots and such
)
'
execute (#query)
--attempt 2
declare #query VARCHAR(MAX)
#query = 'SELECT
--a bunch of stuff involving joins and pivots and such
'
execute (#query)
select * INTO #T1 execute (#query)

One workaround is to use global temp table:
SET #query = 'SELECT * INTO ##T1 FROM (
SELECT
--a bunch of stuff involving joins and pivots and such
)';
EXECUTE(#query);
SELECT * -- reasign to local temp table to avoid reserving global ##T1 name
INTO #T1 -- if needed you can skip this part and work only on global table
FROM ##T1;
DROP TABLE ##T1;
SELECT *
FROM #T1;
LiveDemo
The normal local temporary table won't work, because Dynamic SQL creates new context. The table is in that context and will cease to exist when code is executed, so you cannot use it outside Dynamic-SQL.

Related

If condition not working inside dynamic sql

In below dynamic sql I am trying to check whether temporary table (#Table) already exists if not then create using some other table.
But my problem is that irrespective what is the value in IF condtion, I am always getting error for select statement which is inside If condition
There is already an object named '#Table' in the database.
Below is the sql code.
declare #sqlstring varchar(max)
set #sqlstring=N'
select * into #Table from mst_country
if(object_id(''tempdb..#Table'') is null)
begin
select * into #Table from mst_country_bkp
end'
exec(#sqlstring)
Can any one please let us know why it can be happening?
You need to drop the temp table once you are done with your query like this:
declare #sqlstring varchar(max)
set #sqlstring=N'
IF OBJECT_ID(''tempdb.dbo.#Table'', ''U'') IS NOT NULL
DROP TABLE #Table;
select * into #Table from mst_country
if(object_id(''tempdb..#Table'') is null)
begin
select * into #Table from mst_country_bkp
end'
exec(#sqlstring)
EDIT:
The issue is that you cannot have two SELECT INTO inside the same sql statement. This is a leftover from SQL 6.5 which did not have deferred name resolution. Try this:
declare #sqlstring varchar(max)
set #sqlstring=N'
IF OBJECT_ID(''tempdb.dbo.#Table'', ''U'') IS NOT NULL
DROP TABLE #Table;
select * into #Table from mst_country
insert into #Table(col1,col2,....)
select col1,col2,.... from mst_country_bkp
end'
exec(#sqlstring)
When compiling the sqlserver doesn't allow you creating the same temporary table in the same scope twice. You can actually cheat the sqlserver like this, so it doesn't realize that the temporary table was already created:
declare #sqlstring varchar(max)
set #sqlstring=N'
exec(''select * into #Table from mst_country'')
if(object_id(''tempdb..#Table'') is null)
select * into #Table from mst_country_bkp
'
exec(#sqlstring)

How to get table from EXEC sp_executesql in #TempTable, within a stored procedure

I need some help
My goal:
I have a #query in a stored procedure which is working perfectly. Now I have to perform more operation on the returning table from #query execution within same stored procedure. e.g I have to add more columns in the returning table and add new data from more queries.
My problem:
I am not able to get returning table form (EXEC sp_executesql) into a variable (#TempTable). And one more problem is that the number of columns returning are not known (dynamic).
Steps should be like this:
Declare TempTable
TempTable = EXEC sq_executesql
Add new columns to TempTable
Fill more data
Kindly guide me
this can be achieved using global temp tables like below :
DECLARE #sql NVARCHAR(1000)
DECLARE #Column NVARCHAR(1000)
SET #Column = 'YouColumnList' -- id,name etc. created by you dynamically.
IF( Object_id('tempdb..##IntermediateTable') IS NOT NULL )
DROP TABLE ##IntermediateTable
SET #sql = '
SELECT ' + #Column + '
Into ##IntermediateTable
FROM YourTable
WHERE id = 123
'
EXEC sp_executesql
#sql
IF( Object_id('tempdb..#temptable') IS NOT NULL )
DROP TABLE #temptable
SELECT *
INTO #temptable
FROM ##IntermediateTable
IF( Object_id('tempdb..##IntermediateTable') IS NOT NULL )
DROP TABLE ##IntermediateTable
SELECT *
FROM #temptable --resulting temptable to use. alter it or do whatever desired.

Dropping all local temp tables prior to running a query

I'm debugging a stored procedure by running various pieces of the code manually. The problem is the code creates a lot of temp tables, so I have to add a lot of "DROP TABLE #name" to the start of my query in order for it to work for multiple runs.
Is there a way to drop all temp tables before my query runs?
You can find the solution in an old post here ...
I would suggest first make sure that its only deleting the table you want to delete, by print the query prepared
declare #sql nvarchar(max)
select #sql = isnull(#sql+';', '') + 'drop table ' + quotename(name)
from tempdb..sysobjects
where name like '##%'
select #sql
And then if all table names look good to you. Run with exec(SQL)
EXEC( #sql )
Below is the test I did for this, and it worked for because my temp tables has names starting with '##' which in my cases didn't pulled any global temp tables.
declare #sqlCreate nvarchar(max)
declare #sqldrop nvarchar(max)
--Creating Temp tables
set #sqlCreate = 'create table ##tempTable1( c int, b int, a nvarchar(50) ) ; create table ##tempTable2( c int, b int, a nvarchar(50) )'
EXEC( #sqlCreate )
--Preparing drop statement
select #sqldrop = isnull(#sqldrop+';', '') + 'drop table ' + quotename(name)
from tempdb..sysobjects
where name like '##%'
--Making sure that only my temp tables are returned.
select #sqldrop
--Executing the drop query
EXEC(#sqldrop)

T-Sql getting data from tempdb table

I'm using Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64) and I'm trying to make a SELECT statement to a table that have been created like this:
DECLARE #Sql AS VARCHAR(1500)
SET #Sql = 'SELECT 1 AS id, ''123'' AS value INTO #tmp_prueba'
EXECUTE ( #Sql )
SELECT * FROM #tmp_prueba
But I'm noticed that the table not exists
How can I get the data from the table?
The temporary table that you created in #sql is out-of-scope of the outer query.
Here is one way to do what you want:
DECLARE #Sql AS VARCHAR(1500);
SET #Sql = 'SELECT 1 AS id, ''123'' AS value INTO #tmp_prueba;
select * from #tmp_prueba'
create table #tmp_prueba (id int, value varchar(255));
insert into #tmp_prueba
EXECUTE( #Sql );
SELECT * FROM #tmp_prueba
Here are the changes. FIrst, I select everything from the temproary table in the #sql query. Second, I create a temporary table (with the same name in this case) to hold the results. Now, I can insert the results from the execute into the table. Voila! The data is there.
Temp table are created on Tempdb, therefor you can also do this:
SET #Sql = 'SELECT 1 AS id, ''123'' AS value INTO ##tmp_prueba'
EXECUTE ( #Sql )
Select * from tempdb..##tmp_prueba

Execute sp_executeSql for select...into #table but Can't Select out Temp Table Data

Was trying to select...into a temp Table #TempTable in sp_Executedsql.
Not its successfully inserted or not but there Messages there written
(359 row(s) affected) that mean successful inserted?
Script below
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = 'select distinct Coloum1,Coloum2 into #TempTable
from SPCTable with(nolock)
where Convert(varchar(10), Date_Tm, 120) Between #Date_From And #Date_To';
SET #Sql = 'DECLARE #Date_From VARCHAR(10);
DECLARE #Date_To VARCHAR(10);
SET #Date_From = '''+CONVERT(VARCHAR(10),DATEADD(d,DATEDIFF(d,0,GETDATE()),0)-1,120)+''';
SET #Date_To = '''+CONVERT(VARCHAR(10),DATEADD(d,DATEDIFF(d,0,GETDATE()),0)-1,120)+''';
'+ #Sql;
EXECUTE sp_executesql #Sql;
After executed,its return me on messages (359 row(s) affected).
Next when trying to select out the data from #TempTable.
Select * From #TempTable;
Its return me:
Msg 208, Level 16, State 0, Line 2
Invalid object name '#TempTable'.
Suspected its working only the 'select' section only. The insert is not working.
how fix it?
Using a global temporary table in this scenario could cause problems as the table would exist between sessions and may result in some problems using the calling code asynchronously.
A local temporary table can be used if it defined before calling sp_executesql e.g.
CREATE TABLE #tempTable(id int);
execute sp_executesql N'INSERT INTO #tempTable SELECT myId FROM myTable';
SELECT * FROM #tempTable;
Local temporary table #table_name is visible in current session only, global temporary ##table_name tables are visible in all sessions. Both lives until their session is closed.
sp_executesql - creates its own session (maybe word "scope" would be better) so that's why it happens.
In your #sql string, don't insert into #TempTable. Instead, call your SELECT statement without an INSERT statement.
Finally, insert the results into your temporary table like so:
INSERT INTO #tmpTbl EXEC sp_executesql #sql
Also, you'll need to declare the temporary table if you use this approach
DECLARE #tmpTbl TABLE (
//define columns here...
)
your temp table in dynamic SQL is out of scope in the non dynamic SQL part.
Look here how to deal with this: A bit about sql server's local temp tables
Temporary tables only live as long as the connection that creates them. I would expect that you're unintentionally issuing the select on a separate connection. You can test this by momentarily doing your insert into a non-temporary table and seeing if your data is there. If that is the case you can go back to your original solution and just be sure to pass the connection object to your select.
declare #sql varchar(1000)
set #sql="select * into #t from table;"
set #sql =#sql + "select * from #t;"
execute SP_EXECUTESQL #sql
This worked for me
declare #sql nvarchar(max)
create table #temp ( listId int, Name nvarchar(200))
set #sql = 'SELECT top 10 ListId, Name FROM [V12-ListSelector].[dbo].[List]'
insert into #temp
exec sp_executesql #sql
select * from #temp
drop table #temp
To work around this issue use a CREATE TABLE #TEMPTABLE command first to generate an empty temp table before running sp_executesql. Then run the INSERT INTO #TEMPTABLE with sp_executesql. This will work. This is how I overcome this problem as I have a setup in which all my queries are usually run via sp_executesql.
This one worked for me:
DECLARE #Query as NVARCHAR(MAX);
SET #Query=(SELECT * FROM MyTable) ;
SET #Query=(SELECT 'SELECT * INTO dbo.TempTable FROM ('+#Query +') MAIN;');
EXEC sp_executesql #Query;
SELECT * INTO #TempTable FROM dbo.TempTable;
DROP TABLE dbo.TempTable;
SELECT * FROM #TempTable;
Note, from T-SQL 2021 onwards, dm_exec_describe_first_result_set() can be used to build a temporary table in the right shape to INSERT INTO - as it gives you the column names and types that will be returned from your dynamic SELECT or EXEC ... so you can build dynamic SQL to ALTER a temporary table into the shape you need.
DECLARE #strSQL NVarChar(max) = 'EXEC [YourSP] #dtAsAt=''2022-11-09'', #intParameter2=42'
--*** Build temporary table: create it with dummy column, add columns dynamically
--*** using an exec of sys.dm_exec_describe_first_result_set() and dropping the dummy column
DROP TABLE IF EXISTS #tblResults;
CREATE TABLE #tblResults ([zz] INT);
DECLARE #strUpdateSQL NVarChar(max);
SELECT #strUpdateSQL = STRING_AGG( CONCAT( 'ALTER TABLE #tblResults ADD ',
QUOTENAME([name]), ' ',
[system_type_name], ';')
, ' ') WITHIN GROUP (ORDER BY [column_ordinal])
FROM sys.dm_exec_describe_first_result_set (#strSQL, NULL, 0)
SET #strUpdateSQL += 'ALTER TABLE #tblResults DROP COLUMN [zz];'
EXEC (#strUpdateSQL);
--*** Now we have #tblResults in the right shape to insert into, and use afterwards
INSERT INTO #tblResults EXEC (#strSQL);
SELECT * FROM #tblResults;
--*** And tidy up
DROP TABLE IF EXISTS #tblResults;