Select from temp table fails - sql

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.

Related

How to call table variables outside stored procedure

I want to access outside the scope of a stored procedure a table variable that it defines. I have tried this one, but my case is different because my procedure receives a varchar as a parameter and then it creates a varchar that is executed, someway like this:
create procedure p_x
#Table varchar(250)
as
begin
declare #Sql varchar(450)
select #sql = 'declare ' + #Table + 'table(col1 varchar(10), col2 float, col3 float, col4 float)'
select #sql = #sql + ' insert' + #Table + ' values('a', 1,1,1)'
select #sql = #sql + ' insert' + #Table + ' values('b', 2,2,2)'
select #sql = #sql + ' select * from'
execute(#sql)
end
go
The solution the other question does is to pass as a parameter the new table to be processed. But in my case, because the code is written in a decisive part inside a varchar concatenation (and also it creates auxiliary tables concatenating at the end of the varchar #Table), I don't know what to do.
To give some context: there is this procedure that uses global temporary tables, which were called inside queries. Everything was working fine until we need to change the query to transform it into a table-valued function. The query just access the tables defined inside the procedure through global scope, but the table-valued function doesn't allow to access these global temporary tables. It seems that table variables can't be global.
In short, to change the query to a table-valued function, I need to change the procedure's temporary tables into table variables that I can access inside the table-valued function.
The big picture: 1) Today I have a query that works and this query calls a procedure.
2) I want to be able to call this query from a API without having to paste 100 lines of query
3) I received the suggestion of converting the query into a TFV
4) I did it, but it doesn't work, because TFV can't use temporary tables
5) I want a workaround to create a copy of the procedure with some minor changes that I can call from the TVF.
You cannot do this with a table variable. You can do it with a Temp Table, but table variables are automatically out of scope and inaccessible outside of the procedure that creates them.

How to use a variable in "Select [some calculations] insert into #NameOfTheTableInThisVariable"?

I have a procedure in which there are calculations being done and the final result is inserted into a permanent table. I want to remove the permanent table and I cannot use Temp table as well. So i want to use a dynamic table name, which is stored in a variable:
Current scenario:
Insert into xyz_table
Select col1,col2,sum(col3)
from BaseTable
(In reality, there are lot of columns and a lot of calculations)
What I want:
Select col1,col2,sum(col3) into #DynamicTableName
from BaseTable
where the name of the table would be dynamic in nature i.e.,
#DynamicTableName = 'xyz ' + cast(convert(date,getdate()) as nvarchar)+' '+convert(nvarchar(5),getdate(),108)
It will have date and time in its name every time the procedure is run.
I want to use this name in the "Select * into statement"
How can I achieve this?
i tried it with the some short code. But since my procedure has a lot of calculations and UNIONS , I cannot use that code for this. Any help would be appreciated.
declare #tablename nvarchar(30)= 'xyz ' + cast(convert(date,getdate()) as nvarchar)+' '+convert(nvarchar(5),getdate(),108)
declare #SQL_Statement nvarchar(100)
declare #SQL_Statement2 nvarchar(100)
declare #dropstatement nvarchar(100)
SET #SQL_Statement = N'SELECT * Into ' +'['+#tablename +'] '+'FROM '+ 'dimBranch'
print #SQL_Statement
EXECUTE sp_executesql #SQL_Statement
SET #SQL_Statement= N'select * from ' + '['+#tablename + '] '
print #SQL_Statement
EXECUTE sp_executesql #SQL_Statement
set #dropstatement = 'DROP TABLE' + '['+#tablename + '] '
PRINT #dropstatement
exec sp_executesql #dropstatement
Reason why I want this is because I use this procedure in ETL job as well as in SSRS report. And if someone runs the package and the SSRS report at the same time, the incorrect or weird data gets stored in the table. Therefore I need a dynamic name of the table with date and time.
You can't parameterize an identifier in SQL, only a value
--yes
select * from table where column = #value
--no
select * from #tablename where #columnname = #value
The only thin you can do to make these things dynamic is to build an sql string and execute it dynamically, but your code is already doing this with sp_executesql
More telling is your complaint at the bottom of your question, that if the procedure is invoked simultaneously it gives problems. Perhaps you should consider using local table variables for temporary data storage that the report is using rather than pushing data back into the db
DECLARE #temp TABLE(id INT, name varchar100);
INSERT INTO #temp SELECT personid, firstname FROM person;
-- work with temp data
select count(*) from #temp;
--when #temp goes out of scope it is lost,
--no other procedure invoked simultaneously can access this procedure'a #temp
Consider a local temp table, which is automatically session scoped without the need for dynamic SQL. For example:
SELECT *
INTO #YourTempTable
FROM dimBranch;
The local temp table will automatically be dropped when the proc completes so there is no need for an explict drop in the proc code.

Creating SQL Function to Create Multiple Tables

I am currently moving a SAS process to SQL. Within the SAS process, I leverage macros to create a multitude of tables.
I am trying to leverage the CREATE FUNCTION function within SQL to mimic this process, however I am stuck. I have three arguments, the server name, the name of the new table and the table where it should select from. I'm not sure what I should specify as what I am returning as I'm not looking to return anything, just create tables.
CREATE FUNCTION dbo.functionname (#server VARCHAR(250), #name VARCHAR(250), #table VARCHAR(250))
RETURN (???)
AS BEGIN
SELECT *
INTO #server.dbo.#nm
FROM #table
RETURN
END
This is what I have come up with so far. My SELECT statement wouldn't actually be *, I just put that for simplicity sake for this question.
UPDATE: In this instance, using a stored procedure is not an option as permissions have been limited.
You can create a dynamic SQL script as follows
declare #newtable sysname = 'T003',
#sourcetable sysname = 'sys.tables'
declare #sql nvarchar(max)
set #sql = N'select * into ' + #newtable + ' from ' + #sourcetable + ';'
set #sql = #sql + N'select * from ' + #newtable
exec sp_executesql #sql
Then you can use it in a stored procedure
To return data from new table, the table type must be known before. In this case it is not possible, so developer cannot create the function return type
Or create a function just to create the table and insert data into it. But return fail or success, etc
Then select from the new table using a dynamic SQL again

Select into #temp table got an error

I have complicated store procedure and get the data into the #temp table that is worked fine. However when I filter the data from this temp table then I got the error, 'Invalid object name '#temp_2'. After the data in #temp_2 table, I also need to open into cursor. Would someone tell me how to solve it.
There is my script:
DECLARE #sql varchar(500)
IF #strLocations=''
SET #sql='SELECT * into #temp_2 from #temp_1'
ELSE
SET #sql='SELECT * into #temp_2 from #temp_1 t where t.Location_id in ( ' + #strLocations + ')'
EXEC (#sql)
select * from #temp_2
EXEC creates a new session to execute the statements. When the session ends, any local temporary tables created in it are destroyed (i.e. dropped). You will have to create the temporary table before your EXEC statement.

SQL OpenQuery variable tablename

I need to transfer data from a linked server to our main SQL server. The issue is, that the table name changes everyday.
I have looked around this site to find out if it is even possible to have a variable database name, which it is, but also to see if it is possible to have variables in a OPENQUERY, which it also is.
But i am struggling to combine those needs, so i have a variable table name in a OPENQUERY.
I need something like this:
Declare #LinkedServer as varchar(max) = 'LinkedServer'
Declare #TName as varchar(max) = 'TName'+substring(cast(cast(getdate() as date) as
varchar(50)),1,4)+substring(cast(cast(getdate() as date) as
varchar(50)),6,2)+substring(cast(cast(getdate() as date) as
varchar(50)),9,2)
SELECT * FROM OPENQUERY(#LinkedServer, 'SELECT * FROM dbo.#TName')
Is there any way i can make a variable table name in a OPENQUERY ?
Thank you for your help.
/Mikkel
I'd write a synonym which gets updated every day before you kick off your data extraction job. Then you don't need to be updating (potentially a tonne of) references.
CREATE SYNONYM LinkedTableA
FOR
ServerName.DBName.dbo.TName20170331
SELECT * FROM LinkedTableA
The answer i have, is this:
USE [DataBase]
GO
DROP SYNONYM [dbo].[eCallByCallStat]
GO
declare #tablename varchar(50)
set #tablename = 'Server1..dbo.eCallByCallStat'+substring(cast(cast(getdate()-1 as date) as varchar(50)),1,4)+substring(cast(cast(getdate()-1 as date) as varchar(50)),6,2)+substring(cast(cast(getdate()-1 as date) as varchar(50)),9,2)
declare #sql varchar(500)
set #sql = 'CREATE SYNONYM [dbo].[eCallByCallStat] FOR ' + #tablename
exec (#sql)
This will run everymorning updating the table name in the synonym, and then we will insert that data into a prober table so we have all the data.