如何正确检查 SQL Server 2005 中临时表是否存在?

34

我有一个查询语句,其中我从一个表中插入一些值:

SELECT ID, NAME INTO #tmpTable1
FROM TableOriginal

第一次执行很好,但如果我在 MSSMS(Microsoft Sql Server Management Studio) 中按 F5(运行)键,就会出现以下错误:

Msg 2714, Level 16, State 6, Line 4
已经存在数据库中的一个名为“#tmpTable1”的对象。

很好。我决定在将数据从 TableOriginal 插入到 #tmpTable1 之前进行检查,方法如下:

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

无效,错误仍然如上所述。

我在tempdb数据库中看到了以下临时表名称:

dbo.#tmpTable1__________________0000007

为什么?每次创建临时表(使用第一个查询)时,在 MSSMS 中表名都会自动生成?

如何删除现有的临时表以便使用新值创建新表?

5个回答

63

你已经非常接近了 - 你需要在检查中使用两个点:

IF OBJECT_ID('tempdb..#tmpTable1') IS NOT NULL  
                    ** 
                    |
                  use two dots here!

基本上,这是在说:检查tempDB,我不关心表所在的模式

正如Joe所说:这并非完全正确:它不会检查所有模式 - 它只会检查默认所有者的模式 - 通常为dbo。所以这也可以工作:

IF OBJECT_ID('tempdb.dbo.#tmpTable1') IS NOT NULL  

如果你创建的对象不是默认所有者所在的架构,那么你需要明确指定你要引用的架构。但是tempDB中的临时表确实是在dbo架构中创建的。


LOL,那个额外的点有所不同:)。谢谢。 - Snake Eyes
@MichaelSwan:没错,这就是 SQL Server 的三部分命名方式:db.schema.object - 如果你省略了 schema,仍然需要点号! :-) - marc_s
2
@marc_s:我认为..(双点)指的是默认所有者,即dbo。 - Joe G Joseph
@marc_s:如果我从C# ASP.NET调用,需要DROP表吗?或者使用连接池,会自动删除吗? - Snake Eyes
这里的tempdb也很重要,请不要使用“yourdb..tableName”,我一直在尝试使用“Advantureworksdb..tableName”。 - Thunder
显示剩余3条评论

12

这并不是对问题的回答,只是想临时发布一个关于在引用 #temp 表时使用.dbo...的比较的响应。

我找不到一种方法使 #temp 表实际上归属于除 dbo 以外的任何东西。 尝试一下:

CREATE SCHEMA blat;
GO

CREATE TABLE blat.#pound(id INT);
GO

SELECT 
   OBJECT_ID('tempdb..#pound'), 
   OBJECT_ID('tempdb.dbo.#pound'), 
   OBJECT_ID('tempdb.blat.#pound');

USE tempdb;
GO

SELECT [object_id], SCHEMA_NAME([schema_id]) 
  FROM sys.objects 
  WHERE name LIKE '#pound%';

结果:

-1222354987    -1222354987    -1222354987

-1222354987    dbo

这是在SQL Server 2012上测试的。我在SQL Server 2005上测试,唯一的区别是object_id值为正数。我还尝试了以下内容:

  • tempdb中实际存在一个名为blat的架构
  • 由默认架构为blat的用户创建的表blat.#pound
  • 以上两种情况都有

在所有三种情况下,都达到了与上述相同的结果。

您也不能在不同模式中创建两个同名的#临时表:

CREATE TABLE blat.#flab(id INT);
CREATE TABLE dbo.#flab(id INT);

结果:

Msg 2714, Level 16, State 6
数据库中已经存在名为“#flab”的对象。

这不是一个解析问题(就像许多#temp表问题一样)。您可以分别运行这两个语句并接收相同的错误。

所以,这是说一个冗长的方式,你永远不需要在解析#temp表名称时指定架构,它将始终在dbo下创建,并且至少在OBJECT_ID下的解析将忽略您指定的架构(当在#tempdb上下文中运行时,OBJECT_SCHEMA_NAME也始终返回dbo,但不会在任何其他数据库中返回)。如果您尝试查询tempdb.sys.objects中的schema_id,则所有押注都将失效。


2
CREATE TABLE #temptable (col1 int);
GO
INSERT INTO #temptable
VALUES (10);
GO
SELECT * FROM #temptable;
GO
IF OBJECT_ID(N'tempdb..#temptable', N'U') IS NOT NULL 
DROP TABLE #temptable;
GO
--Test the drop.
SELECT * FROM #temptable;

-1

以这种方式定义的临时表将存在于创建它的连接打开的时间内。通常情况下,没有必要手动检查它是否存在或删除它,因为您在连接内具有完全控制权,但如果您确实需要检查它,可以检查 tempdb.dbo.#tempTable。


-1

IF OBJECT_ID('tempdb.dbo.#tmpTable1%') IS NOT NULL

如果OBJECT_ID('tempdb.dbo.#tmpTable1%')不是空的


如果OBJECT_ID('tempdb.dbo.#tmpTable1')不为NULL,则在2008服务器上执行此操作。对于临时表#,无需检查,但对于##,需要防止在一个会话中重新创建。 - user4521610
1
为什么不用正确的代码更新你的帖子,而是把修正放在评论中呢?这样不太明显。 - rayryeng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接