数据库中已有一个名为“#columntable”的对象

问题描述 投票:0回答:9

我正在尝试以下查询

   if exists (select 1  from emp where eid = 6)     
     begin
        if object_id('tempdb..#columntable') is not null 
          begin 
             drop table #columntable                         
          end                     
        create table #columntable (oldcolumns varchar(100))   
     end
  else
     begin
        if object_id('tempdb..#columntable') is not null 
          begin 
             drop table #columntable            
          end     


    create table #columntable (newcolumns varchar(100))   
 end

但我收到错误

Msg 2714, Level 16, State 1, Line 8
There is already an object named '#columntable' in the database.

任何人都可以建议为什么吗?如果我不写 else 部分,相同的查询可以正常工作。

sql sql-server-2005 t-sql
9个回答
9
投票

不幸的是,这是一个 SQL Server 解析器错误(已由 Microsoft 确认)。

@DizGrizz 也是对的 - 如果在

SELECT .. INTO #SomeTable
语句中重复,
IF .. ELSE
不起作用。


如果..否则..创建表#SomeTempTable

在回答实际问题时,创建然后更改表是可行的(您也只需检查和删除一次)...

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

CREATE TABLE #MyTempTable (DummyColumn BIT)

IF EXISTS (SELECT 1 FROM EMP WHERE EID = 6)     
    BEGIN
        ALTER TABLE #MyTempTable
        ADD MyColumnType1 VARCHAR(100)

        ALTER TABLE #MyTempTable
        DROP COLUMN DummyColumn
    END
ELSE
    BEGIN
        ALTER TABLE #MyTempTable 
        ADD MyColumnType2 VARCHAR(100)

        ALTER TABLE #MyTempTable
        DROP COLUMN DummyColumn
    END


如果..否则..选择#SomeTempTable

我遇到的问题与@DizGrizz相同:

IF .. ELSE
SELECT .. INTO #SomeTable
结合失败。 作为解决方法,可以选择前 0 行(即无行)来创建具有正确列类型的表。 (这使脚本不受列类型更改的影响,也避免了声明每种类型的麻烦。)然后可以使用
INSERT INTO
,前提是将
IDENTITY_INSERT
设置为
ON
以防止错误:

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

-- This creates the table, but avoids having to declare any column types or sizes
SELECT TOP 0 KeyNm
INTO #MyTempTable
FROM dbo.MyDataTable2

-- Required to prevent IDENTITY_INSERT error
SET IDENTITY_INSERT #MyTempTable ON

IF @something = 1
    BEGIN
        -- Insert the actual rows required into the (currently empty) temp table
        INSERT INTO #MyTempTable (KeyNm)
        SELECT KeyNm
        FROM dbo.MyDataTable2
        WHERE CatNum = 2
    END
ELSE
    BEGIN
        -- Insert the actual rows required into the temp table
        INSERT INTO #MyTempTable (KeyNm)
        SELECT KeyNm
        FROM dbo.MyDataTable2
        WHERE CatNum = 8
    END

SET IDENTITY_INSERT #MyTempTable OFF

7
投票

临时表不会在查询结束时自动删除,只有当当前与数据库的连接被删除或者您使用

DROP TABLE #columntable

显式删除它们时

要么在查询开始时测试表是否存在,要么总是在查询结束时删除它(最好两者都删除)

编辑:正如 Matrin 在他的评论中所说,这实际上是一个解析错误。如果您只解析 SQL,就会得到与执行 SQL 时相同的错误。

为了测试这一点,我将您的查询分开并尝试:

if exists (select 1 from emp where id = 6)
  create table #columntable (newcolumns varchar(100))
GO
if not exists (select 1 from emp where id = 6)
  create table #columntable (oldcolumns varchar(100))
GO

解析器对此感到满意。有趣的是,如果您更改为使用非临时表,原始查询可以很好地解析(我意识到会产生问题,我只是想找出查询无法解析的原因)。


2
投票

如果您使用 SELECT INTO... 创建表,也会发生这种情况

IF OBJECT_ID('tempdb..#MyTempTable', 'U') IS NOT NULL
    DROP TABLE #MyTempTable
SELECT TOP 1 @MyVariable = ScaleValue
    FROM MyDataTable1
    WHERE ProductWeight > 1000
IF @MyVariable = 1
BEGIN
    SELECT KeyNm
        INTO #MyTempTable
        FROM dbo.MyDataTable2
        WHERE CatNum = 2
END
ELSE
BEGIN
    SELECT KeyNm
        INTO #MyTempTable
        FROM dbo.MyDataTable2
        WHERE CatNum = 8
END

解析器甚至不应该尝试检测这一点,因为在许多情况下,解析器不可能确定该表是否已经存在。 上面的代码是一个完美的例子......解析器无法确定@MyVariable的值。 我希望有人已经向 MS 通报了这个错误(我听不到他们的耳朵)。


1
投票

您可以通过执行以下操作来检查它是否存在:

IF OBJECT_ID('tempdb..#columntable') IS NOT NULL
BEGIN
DROP TABLE #columntable
PRINT 'Dropped table...'
END

1
投票

使用全局临时表并将 select 包装在 exec 中。

示例:

失败

declare @a int = 1
if object_id('tempdb..##temp') is not null drop table ##temp
if(@a = 1) select * into ##temp from table_1
else if(@a = 2) select * into ##temp from table_2

胜利

declare @a int = 1
if object_id('tempdb..##temp') is not null drop table ##temp
if(@a = 1) exec('select * into ##temp from table_1')
else if(@a = 2) exec('select * into ##temp from table_2')

这会愚弄那些试图变得更聪明的有缺陷的解析器。 微软 - 请解决这个问题。


0
投票

错误是错误的,去掉if子句就可以正常运行了。 因此问题就存在:

if object_id('tempdb..#columntable') is not null
begin
    drop table #columntable
end 

create table #columntable (oldcolumns varchar(100))

0
投票

好吧,我得到了答案... 正如马丁所说,这是一个解析/编译问题。所以我尝试如下更改我的脚本

  if exists (select 1  from emp where eid = 6)     
     begin
        if object_id('tempdb..#columntable') is not null 
          begin 
             drop table #columntable                         
          end                     
        create table #columntable (oldcolumns varchar(100))   
     end
  go
 if exists (select 1  from emp where eid = 1)   
     begin
        if object_id('tempdb..#columntable') is not null 
          begin 
             drop table #columntable            
          end         
        create table #columntable (newcolumns varchar(100))   
     end

这对我有用。


0
投票

我一直遇到这个问题。 我的查询由几个连接的

SELECT
语句组成,其形式为:

DROP TABLE IF EXISTS ##TempTableName

SELECT statement ...

因此,每次我尝试更改 SQL 代码时,都会收到上述错误。我已将所有临时表从 ##global 更改为 #local,现在我可以根据需要多次更改 SQL。所以上面的例子就变成了:

DROP TABLE IF EXISTS #TempTableName

SELECT statement ...

0
投票

在我的例子中,我知道模式在任何一种情况下都是一致的,所以我首先从实时表中提取数据,如果满足特定条件,我从临时表中删除并填充测试表中的数据,从而避免

ELSE
块的一个
INSERT INTO
子句和第二个
IF
语句:

DROP TABLE IF EXISTS #t

SELECT *
INTO #t
FROM tableOfData

IF @pullFromTestTableInstead = 1
BEGIN
    DELETE FROM #t

    INSERT INTO #t
    SELECT *
    FROM tableOfData_TEST
END
© www.soinside.com 2019 - 2024. All rights reserved.