SQL Server 中的临时表导致“已经存在一个名为”的错误

81

我在SQL Server中遇到了以下问题,我的一些代码看起来像这样:

DROP TABLE #TMPGUARDIAN
CREATE TABLE #TMPGUARDIAN(
LAST_NAME NVARCHAR(30),
FRST_NAME NVARCHAR(30))  

SELECT LAST_NAME,FRST_NAME INTO #TMPGUARDIAN  FROM TBL_PEOPLE

当我执行这个操作时,出现了一个错误:“数据库中已经有一个名为'#TMPGUARDIAN'的对象”。有人可以告诉我为什么会出现这个错误吗?

6个回答

105

你正在删除它,然后创建它,并尝试使用SELECT INTO再次创建它。请改为:

DROP TABLE #TMPGUARDIAN
CREATE TABLE #TMPGUARDIAN(
LAST_NAME NVARCHAR(30),
FRST_NAME NVARCHAR(30))  

INSERT INTO #TMPGUARDIAN 
SELECT LAST_NAME,FRST_NAME  
FROM TBL_PEOPLE

在MS SQL Server中,您可以使用SELECT INTO语句创建表格而无需CREATE TABLE语句。


1
我正在使用SELECT INTO而不是CREATE TABLE,但仍然出现错误“数据库中已经存在名为'#MyTempTable'的对象。” - naz786
1
在这种情况下,它必须已经存在了,对于临时表而言,在创建之前包含DROP TABLE IF EXISTS #yourTable;可能会有所帮助。 - Hart CO
是的,我尝试过了,但没有成功。由于 SELECT INTO 对我不起作用,我已经采取了编写两个查询的方法:一个用于创建表,另一个用于插入表中的数据。这对我来说是一种解决方法。无论如何,还是谢谢你。 :) - naz786

52

我通常在存储过程的开头和结尾放置以下这些语句。

这是一个用于检查#temp表是否存在的"exists"检查。

IF OBJECT_ID('tempdb..#MyCoolTempTable') IS NOT NULL
begin
        drop table #MyCoolTempTable
end

完整示例:

(注意,没有任何“SELECT INTO”语句)

CREATE PROCEDURE [dbo].[uspTempTableSuperSafeExample]
AS
BEGIN
    SET NOCOUNT ON;


    IF OBJECT_ID('tempdb..#MyCoolTempTable') IS NOT NULL
    BEGIN
            DROP TABLE #MyCoolTempTable
    END


    CREATE TABLE #MyCoolTempTable (
        MyCoolTempTableKey INT IDENTITY(1,1),
        MyValue VARCHAR(128)
    )  


    INSERT INTO #MyCoolTempTable (MyValue)
        SELECT LEFT(@@VERSION, 128)
        UNION ALL SELECT TOP 3 LEFT(name, 128) FROM sysobjects       

    INSERT INTO #MyCoolTempTable (MyValue)
        SELECT TOP 3 LEFT(name, 128) FROM sysobjects ORDER BY NEWID()

    ALTER TABLE #MyCoolTempTable 
        ADD YetAnotherColumn VARCHAR(128) NOT NULL DEFAULT 'DefaultValueNeededForTheAlterStatement'

    INSERT INTO #MyCoolTempTable (MyValue, YetAnotherColumn)
       SELECT TOP 3 LEFT(name, 128) , 'AfterTheAlter' FROM sysobjects ORDER BY NEWID()


    SELECT MyCoolTempTableKey, MyValue, YetAnotherColumn FROM #MyCoolTempTable



    IF OBJECT_ID('tempdb..#MyCoolTempTable') IS NOT NULL
    BEGIN
            DROP TABLE #MyCoolTempTable
    END


    SET NOCOUNT OFF;
END
GO

输出示例:

1   Microsoft-SQL-Server-BlahBlahBlah DefaultValueNeededForTheAlterStatement

2   sp_MSalreadyhavegeneration  DefaultValueNeededForTheAlterStatement

3   sp_MSwritemergeperfcounter DefaultValueNeededForTheAlterStatement

4   sp_drop_trusted_assembly    DefaultValueNeededForTheAlterStatement

5   sp_helplogreader_agent  DefaultValueNeededForTheAlterStatement

6   fn_MSorbitmaps  DefaultValueNeededForTheAlterStatement

7   sp_check_constraints_rowset DefaultValueNeededForTheAlterStatement

8   fn_varbintohexstr   AfterTheAlter

9   sp_MSrepl_check_publisher   AfterTheAlter

10  sp_query_store_consistency_check    AfterTheAlter

此外,您还可以查看我的答案(关于“#temp表的范围是什么”):https://dev59.com/0GIj5IYBdhLWcg3wk182#20105766


7
在我的情况下,似乎这还不够。即使我在同一个SELECT语句中两次写入相同的"SELECT MyField INTO #TempTable",这也足以导致编译错误。这两个SELECT INTO不能同时被执行,因为它们位于IF THEN ELSE不同的分支中:尽管如此,我也不能两次编写相同的SELECT INTO。 - Johannes Wentu
1
不要使用Select-Into。这是一种“捷径”。创建#tempTable,使用“Insert Into #MyTemp Select Col1,Col2 from dbo.MyTable”语法。 - granadaCoder
如果OBJECT_ID('tempdb..#TMPGUARDIAN')不是NULL 开始 删除表#TMPGUARDIAN 结尾 将LAST_NAME,FRST_NAME选择到#TMPGUARDIAN从TBL_PEOPLE中SELECT * FROM #TMPGUARDIAN - AMRESH PANDEY
1
Amresh,在这种情况下不起作用 - 如其他地方所指出的那样,即使select-into在互斥分支中,仅仅因为有两个相同的临时表,也会导致编译器错误。显然这是lexxer的缺陷。 - RBerman

9

您需要将查询修改为如下形式

CREATE TABLE #TMPGUARDIAN(
LAST_NAME NVARCHAR(30),
FRST_NAME NVARCHAR(30))  

INSERT INTO #TMPGUARDIAN(FRST_NAME,LAST_NAME)
SELECT LAST_NAME,FRST_NAME  FROM TBL_PEOPLE

--为所有临时表清除最后一个会话。总是在最后删除。在您的情况下,如果在尝试删除时该表不存在,有时可能会发生错误。

DROP TABLE #TMPGUARDIAN

避免使用 insert into,因为如果你使用 insert into,那么在未来如果你想通过添加一个新的列来修改临时表,这个列可能会在一些过程后填充(不是与插入同时进行)。那么,在那个时候,你需要重新设计和重构它。

使用表变量 http://odetocode.com/articles/365.aspx

declare @userData TABLE(
 LAST_NAME NVARCHAR(30),
    FRST_NAME NVARCHAR(30)
)

优点 无需使用Drop语句,因为这与变量类似。作用域在执行后立即结束。


3
有时候,您可能会犯一些愚蠢的错误,比如在同一个.sql文件(同一个工作区/标签页中)编写插入查询,因此当您执行插入查询时,您的创建查询已经写在上面并已经执行过,它将再次开始执行,并与插入查询同时执行。
这就是为什么我们会得到对象名称(表名)已经存在的原因,因为它第二次被执行。
所以,请去到一个单独的标签页来编写您要执行的插入、删除或其他查询。
或者使用注释行来引导同一个工作区中所有查询的前面。
CREATE -- …
-- Insert query
INSERT INTO -- …

1

我发现我遇到了同样的问题:

DROP TABLE IF EXISTS #MyTempTable
CREATE TABLE #MyTempTable (
    MyTempTableID INT,
    OtherColID INT
);

但是我通过使用GO语句将语句分开来解决了这个问题。
DROP TABLE IF EXISTS #MyTempTable
GO
CREATE TABLE #MyTempTable (
    MyTempTableID INT,
    OtherColID INT
);

-1
在Azure数据仓库中,有时也会出现这种情况,因为为用户会话创建了临时表。我通过重新连接数据库解决了相同的问题。

这“解决”了问题,因为断开连接删除了临时表。这与原始问题无关。 - RBerman

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