【问题标题】:SQL Server, can't check if #temporary table exists, with if else statementSQL Server,无法使用 if else 语句检查#temporary 表是否存在
【发布时间】:2014-10-24 10:34:12
【问题描述】:

我正在创建一个处理临时表 (#attributeType) 的触发器。由于触发器可以被多次调用,我想确定并检查临时表#attributeType 是否仍然存在。

这是我在触发器主体中检查临时表的代码:

IF OBJECT_ID('tempdb..#attributeType') IS NOT NULL
    BEGIN
        DROP TABLE #attributeType
        SELECT * INTO #attributeType
        FROM attributeType
        PRINT 'IN IF'+   CAST(OBJECT_ID('tempdb..#attributeType') AS NVARCHAR(80))
    END
ELSE
    BEGIN
        SELECT * INTO #attributeType
        FROM attributeType
        PRINT 'IN ELSE'+  CAST(OBJECT_ID('tempdb..#attributeType') AS NVARCHAR(80))
    END

当我通过 F5 选择代码来测试代码时,我收到此错误消息,指出 #attributeType 临时表存在:

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

我知道在存储过程中 #tempTables 将在 sp 结束后立即被删除,但我仍然不明白为什么我的代码是错误的?

注意 当我注释掉 ELSE 块时,代码可以工作。

【问题讨论】:

    标签: sql-server tsql triggers exists temp-tables


    【解决方案1】:

    如果您不需要在 IF..ELSE 语句中执行任何其他操作,您的代码可以简化为:

    IF OBJECT_ID('tempdb..#attributeType') IS NOT NULL
    BEGIN
        DROP TABLE #attributeType
    END
    
    SELECT *
    INTO #attributeType
    FROM attributeType
    

    在这种情况下,您可以避免 There is already an object named... 错误,并且您仍然有临时表。

    【讨论】:

    • 干得好!这可能比接受的答案更好
    【解决方案2】:

    您在OBJECT_ID('tempdb..#attributeType') 上的测试工作正常。您可以通过单独运行它来测试它,而不是在同一批次中使用dropcreate

    问题在于 SQL Server 在运行之前解析整个批处理。如果它知道#attributeType 存在,它将给出错误:

    SELECT * INTO #attributeType
    

    即使您删除了前一行中的表格。

    一种解决方案是在不同的批次中删除表:

    IF OBJECT_ID('tempdb..#attributeType') IS NOT NULL
        DROP TABLE #attributeType
    GO -- new batch
    SELECT * INTO #attributeType ...
    

    另一种解决方案是在不同的范围内创建表:

    IF OBJECT_ID('tempdb..#attributeType') IS NOT NULL
        DROP TABLE #attributeType
    exec ('SELECT * INTO #attributeType ...')
    

    【讨论】:

    • @Andomar-这个解析问题是一种错误吗?
    • 不是错误,只是某种程度的原始性
    • 通过将 GO 放在 Trigger 的主体中,在 GO 语句之前声明的变量在新批次中不可见。我想我将不得不以某种方式处理这个问题。将 If 子句作为第一条语句,然后在触发器主体中添加 GO 并声明所有变量,其余代码不会将触发器分成 2 批并使其失败?
    • 我不认为你可以在触发器中使用go——底部会超出触发器定义。像declare @tmp table (id int identity, col1 varchar(50)) 这样的表变量是否适合您的目的?
    • @Luther: GO 不能放在触发器的主体中,因为它不是 T-SQL 语句; GO 一个由 SQL Server 客户端工具识别的批处理终止符,并且从未传递给 SQL Server。我不确定为什么你有 2 个不同的 SELECT...INTO 语句,但这会有问题。
    猜你喜欢
    • 2013-05-17
    • 1970-01-01
    • 2013-07-21
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 2015-01-30
    • 2017-04-01
    相关资源
    最近更新 更多