5

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

这是片段:

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。

4

4 回答 4

10
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”等结构,并简单地检查代码中所有使用的对象。

于 2008-09-23T13:28:21.727 回答
0

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

于 2008-09-23T13:26:46.177 回答
0

这是我如何让它工作的:

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

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

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
于 2008-09-23T13:42:02.550 回答
0

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

于 2008-09-23T14:06:07.453 回答