ChatGPT解决这个技术问题 Extra ChatGPT

Check if a temporary table exists and delete if it exists before creating a temporary table

I am using the following code to check if the temporary table exists and drop the table if it exists before creating again. It works fine as long as I don't change the columns. If I add a column later, it will give an error saying "invalid column". Please let me know what I am doing wrong.

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
)

select company, stepid, fieldid from #Results

--Works fine to this point

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
    NewColumn            NVARCHAR(50)
)

select company, stepid, fieldid, NewColumn from #Results

--Does not work
Where are you adding the column? can you post the exact code that is giving you an error?
I am adding the column to the table #Results. If you copy the above code and run it for the first time you don't get any error. Now if you add a column to the temp table and add the column to the select statement, it will say column not found (or something like that).
Consider using the following pattern: BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT. If the transaction succeeds, the table will be removed. If it fails, the table will be gone as well (since it was created within the transaction). In any case: No need to check if the table already exists.
Looks like you just need GO statements.

b
bot

I cannot reproduce the error.

Perhaps I'm not understanding the problem.

The following works fine for me in SQL Server 2005, with the extra "foo" column appearing in the second select result:

IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
GO
CREATE TABLE #Results ( Company CHAR(3), StepId TINYINT, FieldId TINYINT )
GO
select company, stepid, fieldid from #Results
GO
ALTER TABLE #Results ADD foo VARCHAR(50) NULL
GO
select company, stepid, fieldid, foo from #Results
GO
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
GO

IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results` CREATE TABLE #Results (Company CHAR(3),StepId INT) select company, stepid from #results now go back to the create statement and add a column fieldid at the end.change select statement to include fieldid and run it.
'tempdb..#name' is exactly what I needed. I was using 'dbo.#name', like a fool. I get the tempdb part, but what's with the double dots?
@Conrad.Dean double dot is an abbreviation for .dbo.
@deutschZuid it's more accurate to say that double dot is the default schema of the user, which is typically dbo (which isn't a great idea, making dbo the default schema for users but that's usually how it goes)
Your code is so different from the OP, that your 'cannot reproduce' statement is meaningless. I'm happy for you that you got it to work a different way.
B
Bo Persson

The statement should be of the order

Alter statement for the table GO Select statement.

Without 'GO' in between, the whole thing will be considered as one single script and when the select statement looks for the column,it won't be found.

With 'GO' , it will consider the part of the script up to 'GO' as one single batch and will execute before getting into the query after 'GO'.


This should be marked as the correct answer. It's not that the SELECT is actually going to run before the create table, It's that it is being parsed and throwing an error prior to being run, because there is an existing table called #Results that doesn't yet have the FieldId column at the time the select statement is parsed. Adding a GO in there separates the query into batches, which are each parsed & run separately.
I cannot believe the disparity in votes between this and the top answer, which changed the code so much - without explaining why - that it was meaningless as a response.
This answer describes Why it fails, and how to fix it. The accepted answer certainly can't reproduce the issue - because it was written different and possibly side-steps the actual problem encountered. I found myself here because I ran into the same issue, and had forgotten that the script is parsed First and that temp objects are part of the session. I now code by writing it as a SP and calling it to debug, that's another way to not have the problem.
I
Ian Boyd

Instead of dropping and re-creating the temp table you can truncate and reuse it

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    Truncate TABLE #Results
else
    CREATE TABLE #Results
    (
        Company             CHAR(3),
        StepId              TINYINT,
        FieldId             TINYINT,
    )

If you are using Sql Server 2016 or Azure Sql Database then use the below syntax to drop the temp table and recreate it. More info here MSDN

Syntax

DROP TABLE [ IF EXISTS ] [ database_name . [ schema_name ] . | schema_name . ] table_name [ ,...n ]

Query:

DROP TABLE IF EXISTS #Results
CREATE TABLE #Results
  (
   Company             CHAR(3),
   StepId              TINYINT,
   FieldId             TINYINT,
  )

It seems the truncate/reuse method would be more efficient than the DROP TABLE IF EXISTS on Sql Server 2016 and Azure Sql Database as well. Is this not the case?
@prdp Why do you suggest DROP TABLE IF Exists for SQL 2016 or Azure? The syntax is available starting SQL 2008. See MSDN link in your answer? Performance factor?
Nevermind. I now realized, DROP TABLE is supported from SQL Server 2008, but the IF EXISTS clause was introduced in 2016.
I use INTO: select * INTO #HistoricoUserTable from dbo.HistoricoUser
Technically there is nothing guaranteeing that the table's schema matches if the temp table already exists. It's likely the same, but you could have been doing something else with the table especially if you're using a generic name like #Results, #Products, or #Customers. This is the main reason I would use drop/create over truncate.
v
vikas

I think the problem is you need to add GO statement in between to separate the execution into batches. As the second drop script i.e. IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results did not drop the temp table being part of single batch. Can you please try the below script.

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
    DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
)

GO

select company, stepid, fieldid from #Results

IF OBJECT_ID('tempdb..#Results') IS NOT NULL
DROP TABLE #Results

CREATE TABLE #Results
(
    Company                CHAR(3),
    StepId                TINYINT,
    FieldId                TINYINT,
    NewColumn            NVARCHAR(50)
)

GO

select company, stepid, fieldid, NewColumn from #Results

Of note; tempdb.. in the code above is very important. It needs to precede your temp table name. Simply checking OBJECT_ID('#Results') is not enough. Temporary tables are stored in the TempDB database. Per Microsoft: TempDB system database is a global resource that is available to all users connected to the instance of SQL Server or connected to SQL Database
Thanks, @iCode. That's the key for dropping the temp tables: it has to be done on tempdb or it won't be gone.
S
S Krishna

This could be accomplished with a single line of code:

IF OBJECT_ID('tempdb..#tempTableName') IS NOT NULL DROP TABLE #tempTableName;   

i must look at this every day
R
Ryan Kohn

This worked for me: social.msdn.microsoft.com/Forums/en/transactsql/thread/02c6da90-954d-487d-a823-e24b891ec1b0?prof=required

if exists (
    select  * from tempdb.dbo.sysobjects o
    where o.xtype in ('U') 

   and o.id = object_id(N'tempdb..#tempTable')
)
DROP TABLE #tempTable;

This is just different syntax for the conditional table drop. It's interesting but doesn't solve the OP's question, and most of it is redundant. If you just check OBJECT_ID(N'tempdb..#Results') is not null then that's enough to prove that the object already exists.
J
Jacob H

Now you can use the below syntax if you are using one of the new versions of SQL Server (2016+).

DROP TABLE IF EXISTS schema.yourtable(even temporary tables #...)

I'm using SSMS 17.3 and this gives Incorrect syntax near the keyword 'IF'.
@StingyJack Because SQL Syntax is not SSMS version related, but SQL Server version related. The IF [NOT] EXISTS clause is available from SQL Server 2016. It does not matter which SSMS version you are using.
I
Ivan Sivak

Just a little comment from my side since the OBJECT_ID doesn't work for me. It always returns that

`#tempTable doesn't exist

..even though it does exist. I just found it's stored with different name (postfixed by _ underscores) like so :

#tempTable________

This works well for me:

IF EXISTS(SELECT [name] FROM tempdb.sys.tables WHERE [name] like '#tempTable%') BEGIN
   DROP TABLE #tempTable;
END;

Caution: That code will detect a table if it was created by any thread. Single # temp tables are created separately per thread/caller to a stored proc, which is why the underscores in the name so that a different copy exists per thread/process. The Object_ID should work ok for the current thread, as long as you are on SQL 2005 or later.
D
DSR

This worked for me,

IF OBJECT_ID('tempdb.dbo.#tempTable') IS NOT NULL 
DROP TABLE #tempTable; 

Here tempdb.dbo(dbo is nothing but your schema) is having more importance.


M
Marcello Miorelli

pmac72 is using GO to break down the query into batches and using an ALTER.

You appear to be running the same batch but running it twice after changing it: DROP... CREATE... edit... DROP... CREATE..

Perhaps post your exact code so we can see what is going on.


This answer should be a comment, as it provides no actual answer.
J
Jacob Griffin

I usually hit this error when I have already created the temp table; the code that checks the SQL statement for errors sees the "old" temp table in place and returns a miscount on the number of columns in later statements, as if the temp table was never dropped.

After changing the number of columns in a temp table after already creating a version with less columns, drop the table and THEN run your query.


a
anonxen

I recently saw a DBA do something similar to this:

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)

This try statement would catch other errors that could occur when attempting to drop the table. This code assumes that the only reason the try would fail is because the table doesn't exist. It would probably work most of the time, but I wouldn't guarantee it. If the try statement does fail for some other reason, you'll get an error when creating the table, because this has masked the real problem with dropping the table.
This works but bad I don't encourage the hard way when there is smart and perfect solution is there. And also, though OP specified 2005 version, try catch block isn't supported in older versions
The other problem with this is the ideology of using try/catch vs logic. You can see more of the debate here: stackoverflow.com/questions/17335217/try-catch-or-if-statement/…
A
Allan F

Note: This also works for ## temp tables.

i.e.

IF OBJECT_ID('tempdb.dbo.##AuditLogTempTable1', 'U') IS NOT NULL
DROP TABLE ##AuditLogTempTable1

Note: This type of command only suitable post SQL Server 2016. Ask yourself .. Do I have any customers that are still on SQL Server 2012 ?

DROP TABLE IF EXISTS ##AuditLogTempTable1

K
KenD

My code uses a Source table that changes, and a Destination table that must match those changes.

-- 
-- Sample SQL to update only rows in a "Destination" Table
--  based on only rows that have changed in a "Source" table
--


--
-- Drop and Create a Temp Table to use as the "Source" Table
--
IF OBJECT_ID('tempdb..#tSource') IS NOT NULL drop table #tSource
create table #tSource (Col1 int, Col2 int, Col3 int, Col4 int)

--
-- Insert some values into the source
--
Insert #tSource (Col1, Col2, Col3, Col4) Values(1,1,1,1)
Insert #tSource (Col1, Col2, Col3, Col4) Values(2,1,1,2)
Insert #tSource (Col1, Col2, Col3, Col4) Values(3,1,1,3)
Insert #tSource (Col1, Col2, Col3, Col4) Values(4,1,1,4)
Insert #tSource (Col1, Col2, Col3, Col4) Values(5,1,1,5)
Insert #tSource (Col1, Col2, Col3, Col4) Values(6,1,1,6)

--
-- Drop and Create a Temp Table to use as the "Destination" Table
--
IF OBJECT_ID('tempdb..#tDest') IS NOT NULL drop Table #tDest
create table #tDest (Col1 int, Col2 int, Col3 int, Col4 int)

--
-- Add all Rows from the Source to the Destination
--
Insert #tDest
Select Col1, Col2, Col3, Col4 from #tSource


--
-- Look at both tables to see that they are the same
--
select *
from #tSource
Select *
from #tDest

--
-- Make some changes to the Source
--
update #tSource
    Set Col3=19
    Where Col1=1
update #tSource
    Set Col3=29
    Where Col1=2
update #tSource
    Set Col2=38
    Where Col1=3
update #tSource
    Set Col2=48
    Where Col1=4

--
-- Look at the Differences
-- Note: Only 4 rows are different. 2 Rows have remained the same.
--
Select Col1, Col2, Col3, Col4
from #tSource
except
Select Col1, Col2, Col3, Col4
from #tDest

--
-- Update only the rows that have changed
-- Note: I am using Col1 like an ID column
--
Update #tDest
    Set Col2=S.Col2,
        Col3=S.Col3,
        Col4=S.Col4
From    (   Select Col1, Col2, Col3, Col4
            from #tSource
            except
            Select Col1, Col2, Col3, Col4
            from #tDest
        ) S
Where #tDest.Col1=S.Col1 

--
-- Look at the tables again to see that
--  the destination table has changed to match
--  the source table.

select *
from #tSource
Select *
from #tDest

--
-- Clean Up
--
drop table #tSource
drop table #tDest

p
pnbps

Yes, "invalid column" this error raised from the line "select company, stepid, fieldid, NewColumn from #Results".

There are two phases of runing t-sql,

first, parsing, in this phase the sql server check the correction of you submited sql string, including column of table, and optimized your query for fastest retreival.

second, running, retreiving the datas.

If table #Results exists then parsing process will check the columns you specified are valid or not, else (table doesn't exist) parsing will be by passsed the checking columns as you specified.


W
Woric

When you change a column in a temp table, you must drop the table before running the query again. (Yes, it is annoying. Just what you have to do.)

I have always assumed this is because the "invalid column" check is done by parser before the query is run, so it is based on the columns in the table before it is dropped..... and that is what pnbs also said.