为什么T-SQL块即使不执行也会出错?

时间:2008-09-23 13:25:41

标签: sql tsql

我正在编写一个(看似)直观的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 个答案:

答案 0 :(得分: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”等构造,并简单地检查代码中所有使用的对象。

答案 1 :(得分:0)

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

答案 2 :(得分: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

答案 3 :(得分:0)

顺便说一句,Oracle中存在类似的问题,使用“execute immediate”子句也有类似的解决方法。