Dynamic Query not writing into temp table - sql

DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(hi)
FROM #hello
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
--select #cols
The above code for some reason is not entering date into the #storage temp table?
Why is that happening?
select #query = 'SELECT *
into #storage
FROM (
SELECT *
FROM #hello) up
PIVOT ( MAX(AFEAmount) FOR hi IN (' + #cols + ') ) AS pvt'
exec(#query)

The code is crete the temp table #storage. The problem is that the table is not "in scope", so you cannot access it outside the exec() statement. Temporary tables are limited in scope to the particular process that creates them. The temporary table is available when exec() is running but not outside it. There is some explanation of this in the documentation (here).
In some cases, you can get around this by using the insert . . . exec() form of the statement. If the table were permanent, you would construct the create table statement for it, and then do:
insert into storage(...)
exec(#query);
Or, you could even do this inside the dynamic SQL, because the permanent table persists across sessions.
The problem with the temporary table, in this case, is that you don't know its structure. You need to create the table before doing the insert. A variable structure requires dynamic SQL, and you have the same problem when creating the table. It is created at the "wrong" lvel.
You could change the table to a global temporary table (those that begin with ##). This has scoping across different processes.
Or, you could create a persistent table with a funky name (I would use _storage or _storage_YYYYMMDDHHMMSS where the latter has a time stamp at the end). Just remember to delete the table when you are done.

Related

How to dynamically create and populate a local temp table (when the table headers are unknown)?

I am currently using code similar to the following:
SET #Query = 'SELECT * INTO #Temp FROM MyTable'
EXEC sp_executesql #Query
Obviously, this does not work. Until now, I have been getting around this problem by using global temporary tables within my dynamic sql. However, this is not an option once the stored procedure is released to users, as their global temp tables would conflict with one another.
How might I get around this issue? I must specify that the structure of the table MyTable is unknown, so creating the temp table outside of the dynamic sql is (presumably?) not an option.
Edit: Apologies if I was not specific enough with exactly what I am trying to achieve - I thought it would be best to keep this question as relevent to the actual issue as possible.
Obviously, the string that I am trying to execute is not fixed. It is instead constructed so that the table, from which the data is being retrieved, may be specified. Although still not overly complex, the actual query string that I am using is more along the lines of
#Query = CONCAT('SELECT * INTO #Temp FROM ', #Environment, '.[schema].', #Table)
Hopefully this sheds more light on the problem?
Few points:
1. If you want to store the output of dynamic sql into temp table, you need to create the temp table structure first(with CREATE TABLE #TEMP script) and then you can insert data by doing something like below:
INSERT INTO #TEMP EXEC sp_executesql #Query
This will populate data into temp table with all properties of local temp table.
Seeing your query, it does not look like you have a need of dynamic sql unless you are forming some clause like where clause dynamically.
Let me know if this helps.
Couldn't you do something like this:
declare #query nvarchar(4000) = '
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].[temp]'') AND type in (N''U''))
begin
drop table temp
end
Select top 2 *
into temp
from sys.databases
'
exec sp_executesql #query
Select * from temp
With Select into you don't need to know the structure of your query:
https://www.w3schools.com/sql/sql_select_into.asp
Just as an idea.

Dynamic PIVOT query - How to save it in SQL Server?

I had to built a dynamic PIVOT in SQL Server as described in this article using the following script:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(Course)
FROM (SELECT DISTINCT Course FROM #CourseSales) AS Courses
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT Year, ' + #ColumnName + '
FROM #CourseSales
PIVOT(SUM(Earning)
FOR Course IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
It works great and it returns a dynamic table as expected.
However, I would like to be able to select it in an other query but can not find a proper way to do so:
A view does not work as it does not accept variables
A table valued function does not work as I don't know in advance the structure of the output table
A stored procedure does not work as I can not use it in a SELECT query
What would be the best solution to save this dynamic pivot query and be able to SELECT it afterwards?
Thank you
Sylvain
Oh. You can use temp table, my friend. The first, check the exists of temp table. And remember drop it at the end of query.
You could try to use the stored procedure and in that sp use the SELECT INTO in the dynamic pivot query and store in a temporary table (#myDynamicPivot).
Then you can use the temporary table in your next selects statements. Make sure you drop your table after using it.
Edit
I would consider moving that data that the pivot table is created against to a data warehouse and create an analysis database over it. This way you can query using the dimensions and the data will be much faster and it will be more optimized for storage and query.

Select from temp table fails

I'm inserting data into a temp table and querying the temp table fails
DECLARE #SQLQuery AS NVARCHAR(500)
SET #SQLQuery = 'SELECT Top 100 *
INTO #tempTable
FROM ' + #origDB + '.dbo.' + #origTable + ' o WITH (NOLOCK) '
EXECUTE sp_executesql #SQLQuery
and when I try to query the temp table , like so
select * from #tempTable
I get the following error :
Invalid object name '#tempTable'.
Courtesy of MSDN
The problem that you have is with the scope. The TEMP table is creatd at the scope of the EXEC() method and hence it is not available after the function returns. To fix this, create your temp table before calling EXEC() and use an INSERT INTO instead of SELECT INTO.
As others have said, the scope of a temporary table is limited to the session context in which it is created - a stored procedure runs in its own context.
You could use a global temporary table ##tempTable, but it's generally a bad idea as it would be available to other sessions than the one creating it.

Referencing a table variable in a query string

I have created a temprary table variable, which I then need to pivot:
Declare #TempTable TABLE(
Name varchar(150),
CloseDate Date,
Revenue Float)
.... <add data to it> .....
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(CloseDate)
FROM #TempTable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Name, ' + #cols + ' from
(select
t.Name,
t.CloseDate,
t.Revenue
from #TempTable as t
) x
pivot
(SUM(Revenue)
for CloseDate in (' + #cols + ')
) p '
execute(#query)
However, I am getting this error:
Must declare the scalar variable "#TempTable".
When I test the #TempTable variable using a normal SELECT it works fine:
SELECT * from #TempTable
How can I reference the variable successfully in the query string?
Unfortunately when you use execute and sp_executesql they are run within their own context, so they cannot reference table variable objects which are defined outside the scope of the dynamic SQL.
In cases like this, what I have tended to do is create a temp table instead and embed a GUID in the name of the temp table that gets created in tempdb. This ensures the table name is unique for simultaneous operations, and then I place that guid in the dynamic SQL that is created.
Performance wise it's slightly slower but still quick, but whether that is an issue for you or not depends on the number of times this will be executed and the frequency.
After some discussion with Damien in the comments to this answer we've determined that local temp tables (single hashtag) can be used when executing dynamic SQL.
Therefore if you change your declare table variable to CREATE TABLE #TempTable and change the reference in your dynamic SQL this should work properly for you.
The only concern I have about using temp tables is the persistence of objects if your calling code uses some form of connection pooling which doesn't sound like it's the case here.
However, as a general self-paranoid self practice I like to throw one of these before the create table and at the end of the statement to clean up the objects.
IF OBJECT_ID(N'tempdb..#TempTable') IS NOT NULL
DROP TABLE #TempTable
CREATE TABLE #TempTable (Value VARCHAR(50));

Creating a dynamic table from dynamic SQL

First of all I'm using ms SQL server 2012. I' trying to use a table based on a string value passed in as a string into a procedure. I found out that you can't use strings are table names when writing a query so I'm trying to find a way around that. The only lead I'm kind of onto is using dynamic SQL which I also am not sure how to make work. Here is what I have:
DECLARE #q AS NVARCHAR(MAX)
SET #q = 'SELECT * FROM ' + #tableName
DECLARE #tableCopy AS EXECUTE(#q)
How can I get the executed #q into #tableCopy? Or is there a better way to access my table when all I know is the tables name as a string?
You can create the temporary table and then insert into that table inside the dynamic sql. There's an example here:
http://smehrozalam.wordpress.com/2009/10/14/t-sql-using-result-of-a-dynamic-sql-query-in-a-variable-or-table/
Unfortunately, you would need to know the schema. The following does not work:
declare #query varchar(max) =
'select * into #t from table'
EXEC(#query)
select * FROM #t