在创建临时表之前检查临时表是否存在,并删除是否存在


662

我正在使用以下代码检查临时表是否存在,并在重新创建之前删除该表是否存在。只要我不更改列,它就可以正常工作。如果以后再添加一列,则会显示“无效列”错误。请让我知道我在做什么错。

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

您在哪里添加该列?您可以张贴出错误的确切代码吗?
Macros

我将列添加到表#Results中。如果您复制上述代码并首次运行,则不会出现任何错误。现在,如果将一列添加到temp表中并将该列添加到select语句中,它将显示未找到列(或类似的内容)。
斯里达尔2009年

22
考虑使用以下模式:BEGIN TRANSACTION; CREATE TABLE #Results; ...; DROP TABLE #Results; COMMIT。如果交易成功,该表将被删除。如果失败,该表也将消失(因为它是在事务中创建的)。无论如何:无需检查表是否已经存在。
Heinzi 2012年

1
看起来您只需要GO语句。
sam yi

Answers:


733

我无法重现该错误。

也许我不了解这个问题。

在SQL Server 2005中,以下内容对我来说很好用,第二个选择结果中显示了额外的“ foo”列:

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

1
如果OBJECT_ID('tempdb ..#Results')不是空删除表#Results`创建表#Results(Company CHAR(3),StepId INT)选择公司,则#results中的stepid现在返回到create语句并添加一个end.change select语句中的字段fieldid包含字段id并运行它。
里德哈

28
'tempdb..#name'正是我所需要的。我一直在使用'dbo.#name',像个傻瓜。我得到了tempdb一部分,但是双点代表什么呢?
Conrad.Dean 2012年

77
@ Conrad.Dean双点是.dbo的缩写。
deutschZuid 2012年

32
@deutschZuid,更准确地说,双点是用户的默认架构,通常是dbo(这不是一个好主意,使dbo成为用户的默认架构,但这通常是这样)
jcollum

8
您的代码与OP截然不同,以至于您的“无法再现”语句毫无意义。很高兴您能以一种不同的方式工作。
杰拉德·奥尼尔

85

该声明应具有顺序

  1. 更改表的语句
  2. 选择语句。

在两者之间没有'GO'的情况下,整个过程将被视为一个脚本,并且当select语句查找该列时,将不会找到它。

使用'GO',它将把直到'GO'的脚本部分视为一个批处理,并在'GO'之后进入查询之前执行。


7
应该将其标记为正确答案。这并不是说SELECT实际上要在创建表之前运行,而是因为它已经被解析并在运行之前引发错误,因为存在一个名为#Results的现有表,但该表中没有FieldId列。 select语句被解析的时间。在其中添加GO可以将查询分为多个批处理,每个批处理分别解析并运行。
达沃斯

2
我不敢相信此答案与最高答案之间的选票差距,这极大地改变了代码-在没有解释原因的情况下-作为回应毫无意义。
underscore_d

63

dropping您可以代替并重新创建临时表,truncate然后重新使用它

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

如果使用Sql Server 2016Azure Sql Database然后使用以下语法删除临时表并重新创建它。更多信息在这里MSDN

句法

DROP TABLE [如果存在] [database_name。[schema_name]。| schema_name。] table_name [,... n]

查询:

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

看来该truncate/reuse方法将比DROP TABLE IF EXISTSon Sql Server 2016和on 更为有效Azure Sql Database。不是吗?
JDawg '17

@prdp为什么建议DROP TABLE IF Exists使用SQL 2016或Azure?从SQL 2008开始就可以使用该语法。请参见答案中的MSDN链接?性能因素?
HappyTown

4
没关系。我现在意识到,DROP TABLESQL Server 2008对此提供了支持,但该IF EXISTS条款于2016
。– HappyTown

1
我使用INTO从dbo.HistoricoUser中选择* INTO #HistoricoUserTable
Kiquenet,

54

我认为问题在于您需要在两者之间添加GO语句以将执行分为几批。作为第二个删除脚本,即IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results没有删除临时表作为单个批处理的一部分。您可以尝试以下脚本吗?

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

1
值得注意的 tempdb..在上面的代码中非常重要。它必须在您的临时表名称之前。仅仅检查OBJECT_ID('#Results')是不够的。临时表存储在TempDB数据库中。每微软:TempDB的系统数据库是一个全球性的资源,可用于连接到SQL Server的实例或连接到SQL数据库的所有用户
的iCode

谢谢@iCode。这是删除临时表的关键:它必须完成, tempdb否则就不会消失。
亚历克斯

37

只需一行代码即可完成:

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

1
我必须每天看一下
Ab Bennett

28

这对我有用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;

1
对于条件表删除,这只是不同的语法。这很有趣,但是不能解决OP的问题,而且大多数都是多余的。如果仅检查OBJECT_ID(N'tempdb ..#Results')不为null,则足以证明该对象已存在。
达沃斯

21

我这边只提一点评论,因为这OBJECT_ID对我不起作用。它总是返回

`#tempTable不存在

..即使确实存在。我只是发现它以不同的名称(用_下划线后缀)存储,如下所示:

#tempTable________

这对我来说很好:

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

6
警告:该代码将检测到表是否由任何线程创建。每个线程/调用者分别为存储的proc创建单个#临时表,这就是名称中下划线的原因,以便每个线程/进程都存在一个不同的副本。只要您使用的是SQL 2005或更高版本,Object_ID就可以在当前线程上正常运行。
Bytemaster

12

现在,如果您使用的是SQL Server(2016+)的新版本之一,则可以使用以下语法。

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

1
我正在使用SSMS 17.3,这给了Incorrect syntax near the keyword 'IF'.
StingyJack

7
@StingyJack因为SQL语法与SSMS版本无关,但与SQL Server版本相关。该IF [NOT] EXISTS子句可从SQL Server 2016获得。使用哪个SSMS版本都没有关系。
强的松

10

pmac72正在使用GO将查询分解为多个批次,并使用ALTER。

您似乎正在运行同一批,但在更改后又运行了两次:DROP ... CREATE ...编辑... DROP ... CREATE ..

也许发布您的确切代码,以便我们可以看到发生了什么。


7

创建临时表后,通常会遇到此错误;检查SQL语句是否有错误的代码会在适当的位置看到“旧的”临时表,并在以后的语句中返回错误的列数计数,就好像从未删除过该临时表一样。

在已经创建了具有较少列的版本之后更改了临时表中的列数之后,请删除该表,然后运行查询。


6

我最近看到DBA做了类似的事情:

begin try
    drop table #temp
end try

begin catch 
    print 'table does not exist'
end catch 

create table #temp(a int, b int)

2
该try语句将捕获尝试删除表时可能发生的其他错误。该代码假定尝试失败的唯一原因是因为该表不存在。它可能在大多数时间都有效,但我不能保证。如果try语句由于其他原因而失败,则在创建表时会出现错误,因为这掩盖了删除表的实际问题。
达沃斯

这行得通,但是很糟糕,当有一个聪明而完美的解决方案时,我不鼓励采用艰难的方式。而且,尽管OP指定2005版,但旧版本不支持try catch块
dejjub-AIS

另一个问题是使用try / catch vs逻辑的思想。您可以在这里看到更多辩论:stackoverflow.com/questions/17335217/try-catch-or-if-statement/…–
Logixologist

3

我的代码使用一个Source更改的Destination表和一个必须与这些更改匹配的表。

-- 
-- 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

1

是的,“列无效”,此错误是从“选择#Results中的公司,stepid,fieldid,NewColumn”行引发的。

运行t-sql有两个阶段,

首先,进行解析,在此阶段中,SQL Server将检查您提交的sql字符串(包括表的列)的更正,并优化查询以实现最快的恢复。

第二,运行,检索数据。

如果表#Results存在,则解析过程将检查您指定的列是否有效,否则(表不存在)解析将通过您指定的检查列。


0

更改临时表中的列时,必须先删除表,然后再次运行查询。(是的,这很烦人。这就是您要做的。)

我一直以为这是因为“无效列”检查是在运行查询之前由解析器完成的,因此它基于表中被删除之前的列.....这就是pnbs所说的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.