【问题标题】:Why does a T-SQL block give an error even if it shouldn't even be executed?为什么即使不应该执行 T-SQL 块也会出错?
【发布时间】:2010-09-12 08:48:54
【问题描述】:

我正在编写一个(看似)直截了当的 SQL sn-p,它在确保列存在后删除该列。
问题:如果该列不存在,IF 子句inside 的代码会抱怨找不到该列!嗯,doh,这就是它在 IF 子句中的原因!
所以我的问题是,为什么一段不应该执行的代码会出错?

这是sn-p:

IF exists (select * from syscolumns
    WHERE id=object_id('Table_MD') and name='timeout')
BEGIN
    ALTER TABLE [dbo].[Table_MD]
        DROP COLUMN timeout
END
GO

...这是错误:

Error executing SQL script [...]. Invalid column name 'timeout'

我使用的是 Microsoft SQL Server 2005 Express Edition。

【问题讨论】:

    标签: sql tsql


    【解决方案1】:
    IF exists (select * from syscolumns
        WHERE id=object_id('Table_MD') and name='timeout')
    BEGIN
        DECLARE @SQL nvarchar(1000)
        SET @SQL = N'ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout'
        EXEC sp_executesql @SQL
    END
    GO
    

    原因: 当 Sql server 编译代码时,他们会检查它是否有使用过的对象(如果它们存在的话)。此检查过程忽略任何“IF”、“WHILE”等结构,只检查代码中所有使用的对象。

    【讨论】:

    • 正确。如果存储过程使用了临时表,您也会收到此错误。
    • 澄清一下,如果存在临时表,则在编译存储过程时将检查列。在 sproc 实际创建表的地方(例如使用 select into),您可能需要在重新编译 sproc 之前删除表。
    【解决方案2】:

    它可能永远不会被执行,但它会被 Sql Server 解析为有效性。 “解决”这个问题的唯一方法是构造一个动态 sql 块,然后有选择地执行它

    【讨论】:

      【解决方案3】:

      这是我如何让它工作的:

      在 IF 子句中,我将 ALTER ... DROP ... 命令更改为 exec ('ALTER ... DROP ...')

      似乎 SQL 服务器在解析代码时对代码进行了有效性检查,并发现在某处引用了一个不存在的列(即使该段代码永远不会被执行)。
      使用exec(ute) 命令将有问题的代码包装在一个字符串中,解析器不会抱怨,代码只会在必要时执行。 这是修改后的sn-p:

      IF exists (select * from syscolumns
          WHERE id=object_id('Table_MD') and name='timeout')
      BEGIN
          exec ('ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout')
      END
      GO
      

      【讨论】:

        【解决方案4】:

        顺便说一句,Oracle 中也有类似的问题,使用“立即执行”子句的类似解决方法。

        【讨论】:

          猜你喜欢
          • 2016-07-02
          • 1970-01-01
          • 2020-12-24
          • 1970-01-01
          • 1970-01-01
          • 2018-06-25
          • 1970-01-01
          • 2021-12-02
          • 2014-01-09
          相关资源
          最近更新 更多