Don't know temp tables when use Execute in SQL Server - sql

I have below Query :
if OBJECT_ID('tempdb..#tmpTables') is not null
drop table #tmpTables
Execute('select TABLE_NAME into #tmpTables from '+#dbName+'.INFORMATION_SCHEMA.TABLES')
while (select COUNT(*) from #tmpTables)>0
begin
//here is my statement
end
When I execute this Query, I am getting this error :
Invalid object name '#tmpTables'.
But when the query is changed to this :
if OBJECT_ID('tempdb..#tmpTables') is not null
drop table #tmpTables
select TABLE_NAME into #tmpTables from INFORMATION_SCHEMA.TABLES
while (select COUNT(*) from #tmpTables)>0
begin
//here is my code
end
It works.
How can I do this ?

Table names prefixed with a single number sign (#) are 'Local temporary table' names.
Local temporary tables are visible only to their creators during the same connection to an instance of SQL Server as when the tables were first created or referenced.
Local temporary tables are deleted after the user disconnects from the instance of SQL Server.
And when you create a Local Temporary Table by EXEC() command the creator will not be you and it will disconnected after finishing the statement, And as finishing the connection temp table dropped.
You can use a table variable like this:
DECLARE #tmpTables TABLE(TABLE_NAME nvarchar(max))
insert into #tmpTables
(select TABLE_NAME from INFORMATION_SCHEMA.TABLES)

Related

How to write a query which selects from a table that is returned by another query

I have table which has basically 2 rows containing the name of failure and the main table i want to write a query such that
Select main
from xyz
will return the table name like abc.
Now I want to get the data from the abc table
Select *
from
(select main
from xyz)
which returns abc.
How can I write it ?
You must use dynamic sql.
Note, that you can't use "SELECT to nowhere" in a compound statement in Db2. That is, the following code is erroneous.
BEGIN
SELECT * FROM MYTAB;
END#
This is why you need to store the result of SELECT somewhere. You may use Global Temporary Tables for that presuming, that USER TEMPORARY TABLESPASE is available to use for your user.
--#SET TERMINATOR #
BEGIN
DECLARE V_STMT VARCHAR (500);
SELECT
'DECLARE GLOBAL TEMPORARY TABLE SESSION.RESULT'
|| ' AS (SELECT * FROM '
|| MAIN
|| ') WITH DATA WITH REPLACE '
|| 'ON COMMIT PRESERVE ROWS NOT LOOGED'
INTO V_STMT
FROM XYZ
-- place your WHERE clause here if needed
FETCH FIRST 1 ROW ONLY
;
EXECUTE IMMEDIATE V_STMT;
END
#
SELECT * FROM SESSION.RESULT
#
dbfiddle link.
Here is a solution on stack that shows how to get the table names from your database
DB2 Query to retrieve all table names for a given schema
Then you could take your failure table and join into it based off of the table name, that should match your errors to the table that match on the table name. I'm not a 100% sure of your question but I think this is what you are asking.
The inner system query has schema and name. Type is T for table. See IBM link below for column reference. You could run the query wide open in the inner query to look for the tables you want. I would recommend using schema to isolate your search.
https://www.ibm.com/docs/en/db2-for-zos/11?topic=tables-systables
SELECT
ft.*
, st.*
FROM [FailureTable] as ft
INNER JOIN
(
select * from sysibm.systables
where CREATOR = 'SCHEMA'
and name like '%CUR%'
and type = 'T'
) st
ON st.[name] = ft.[tablename]
You can try
DECLARE #tableName VARCHAR(50);
SELECT #tableName = main
FROM xyx
EXEC('SELECT * FROM ' + 'dbo.' + #tableName)
Dont forget to add validation if #tableName doesnt get populated

Use two insert into statements in a stored procedure

I tried to use two insert into statements in one stored procedure like this:
CREATE PROCEDURE dbo.test
AS
BEGIN
DROP TABLE IF EXISTS #temp;
SELECT *
INTO #temp
FROM sys.column_master_keys AS CMK;
-- some statement
-- some statement
-- some statement
DROP TABLE IF EXISTS #temp;
SELECT *
INTO #temp
FROM INFORMATION_SCHEMA.COLUMNS AS C;
END;
Error message :
There is already an object named '#temp' in the database.
How to use one temporary table for many insert into in one stored procedure?
This is occurring because the code is compiled before it is run. During the compilation phase, SQL Server sees the two INSERT statements that create the table. It does not execute them, because it is only devising the execution plans.
Because the code is not being executed, the compilation phase misses the DROP TABLE. Alas. It sees that the table already exists when the second is executed, generating the error.
In any case, this is very easily fixed by giving the tables different names.
You can use one temporary table for many insert into statements in one stored procedure.To make it happen you have to use dynamic SQL.
CREATE PROCEDURE dbo.test
AS
BEGIN
DROP TABLE IF EXISTS #temp;
EXEC('SELECT *
INTO #temp
FROM sys.column_master_keys AS CMK;')
-- some statement
-- some statement
-- some statement
DROP TABLE IF EXISTS #temp;
EXEC('SELECT *
INTO #temp
FROM INFORMATION_SCHEMA.COLUMNS AS C;')
END;

Finding #temp table in sysobjects / INFORMATION_SCHEMA

I am running a SELECT INTO statement like this so I can manipulate the data before finally dropping the table.
SELECT colA, colB, colC INTO #preop FROM tblRANDOM
However when I run the statement and then, without dropping the newly created table, I then run either of the following statements, the table isn't found? Even scanning through object explorer I can't see it. Where should I be looking?
SELECT [name] FROM sysobjects WHERE [name] = N'#preop'
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '#preop'
Temp tables aren't stored in the local database, they're stored in tempdb. Also their name isn't what you named them; it has a hex code suffix and a bunch of underscores to disambiguate between sessions. And you should use sys.objects or sys.tables, not the deprecated sysobjects (note the big warning at the top) or the incomplete and stale INFORMATION_SCHEMA views.
SELECT name FROM tempdb.sys.objects WHERE name LIKE N'#preop[_]%';
If you are trying to determine if such an object exists in your session, so that you know if you should drop it first, you should do:
IF OBJECT_ID('tempdb.dbo.#preop') IS NOT NULL
BEGIN
DROP TABLE #preop;
END
In modern versions (SQL Server 2016+), this is even easier:
DROP TABLE IF EXISTS #preop;
However if this code is in a stored procedure then there really isn't any need to do that... the table should be dropped automatically when the stored procedure goes out of scope.
I'd prefer to query tempdb in such manner:
IF EXISTS (SELECT * FROM tempdb.sys.objects
WHERE object_id = OBJECT_ID(N'tempdb.[dbo].[#MyProcedure]')
AND type in (N'P', N'PC'))
BEGIN
print 'dropping [dbo].[#MyProcedure]'
DROP PROCEDURE [dbo].[#MyProcedure]
END
GO
Below is how I got the columns for a temporary table:
CREATE TABLE #T (PK INT IDENTITY(1,1), APP_KEY INT PRIMARY KEY)
SELECT * FROM tempdb.INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME LIKE '#T%'

Can't select from a successfully created #temp table

DECLARE #tmp_tab VARCHAR(20)
SELECT #TMP_TAB = '#TMP_TAB_BANK' + CAST(USER_ID(USER) AS NVARCHAR)
+ CAST(##SPID AS NVARCHAR)
EXEC('CREATE TABLE ' + #TMP_TAB + (ID INT NULL, NAME VARCHAR NULL)')
//Break point
EXEC('select * from ' + #TMP_TAB)
I'm working in SQL Server 2005. In the code above I decide what to name my temp table. Then I create the temp table. If I run just these codes I receive Commands completed successfully message.
However if I execute the last line of code to retrieve the data (well, I know it's empty) I get
invalid object name '#TMP_TAB_BANK157'
Why can't I fetch records from a just created table? If the temp table was not created then why don't I get any warning?
#TEMP tables are only available from the context they are created in. If you create #temp1 in one spid or connection, you can't access it from any other scope, except for child scopes.
If you create the #TEMP table in dynamic SQL, you need to select from it in the same scope.
Alternatives are:
##GLOBAL temp tables, which have their own risks.
Real tables

What's the scoping rule for temporary tables within exec within stored procedures?

Compare the following stored procedures:
CREATE PROCEDURE testProc1
AS
SELECT * INTO #temp FROM information_schema.tables
SELECT * FROM #temp
GO
CREATE PROCEDURE testProc2
AS
EXEC('SELECT * INTO #temp FROM information_schema.tables')
SELECT * FROM #temp
GO
Now, if I run testProc1, it works, and #temp seems to only exist for the duration of that call. However, testProc2 doesn't seem to work at all, since I get an Invalid object name '#temp' error message instead.
Why the distinction, and how can I use a temp table to SELECT * INTO if the source table name is a parameter to the stored procedure and can have arbitrary structure?
Note that I'm using Microsoft SQL Server 2005.
From BOL:
Local temporary tables are visible
only in the current session... ...
Temporary tables are automatically
dropped when they go out of scope,
unless explicitly dropped using DROP
TABLE
The distinction between your first and second procedures is that in the first, the table is defined in the same scope that it is selected from; in the second, the EXEC() creates the table in its own scope, so the select fails in this case...
However, note that the following works just fine:
CREATE PROCEDURE [dbo].[testProc3]
AS
SELECT * INTO #temp FROM information_schema.tables
EXEC('SELECT * FROM #temp')
GO
And it works because the scope of EXEC is a child of the scope of the stored procedure. When the table is created in the parent scope, it also exists for any of the children.
To give you a good solution, we'd need to know more about the problem that you're trying to solve... but, if you simply need to select from the created table, performing the select in the child scope works just fine:
CREATE PROCEDURE [dbo].[testProc4]
AS
EXEC('SELECT * INTO #temp FROM information_schema.tables; SELECT * FROM #temp')
GO
You could try using a global temp table (named ##temp not #temp). However be aware that other connections can see this table as well.