Sql server &引用;无效的列名";抛出到无法访问的脚本块中

Sql server &引用;无效的列名";抛出到无法访问的脚本块中,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我设计了一个大型sql脚本,可以在不同的实例上运行,或者在同一个实例上运行多次,而不会导致任何坏数据或错误 在编写此类脚本时,我始终依赖以下语法: if not exists (select 1 from SYS.FOREIGN_KEYS where NAME = 'FK_BAR') begin alter table [MyTable] add constraint FK_BAR foreign key (some_id) references Other_Table(some_i

我设计了一个大型sql脚本,可以在不同的实例上运行,或者在同一个实例上运行多次,而不会导致任何坏数据或错误

在编写此类脚本时,我始终依赖以下语法:

if not exists (select 1 from SYS.FOREIGN_KEYS where NAME = 'FK_BAR')
begin
  alter table [MyTable]
    add constraint FK_BAR foreign key (some_id) references Other_Table(some_id)
end
go
这通常效果很好。然而,我最近遇到了一个场景,我无法防止在执行过程中抛出错误。在下面的代码中,已从表Foo中删除列“不推荐使用的_列”:

if     exists (select 1 from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'Foo' and COLUMN_NAME = 'deprecated_column')
   and exists (select 1 from [Foo] where new_column is null)
begin
    declare @updated int set @updated = 1;

    while @updated > 0
    begin
        update top (500000)
               Foo
           set new_column = deprecated_column
         where new_column is null
        ;
        set @updated = @@rowcount;
    end
end
go
如果我独立于此程序运行
If
中的两个
exist
,它们将返回预期的“no results”,这意味着内部代码将永远不会执行。但是,当我运行脚本时,服务器抛出错误:
无效的列名“deprecated_column”。
,并且脚本被标记为已完成但有错误,这会导致在我们的系统上发出警报(即,DBA收到通知并必须进行检查),这会在一个简单的自动化任务上造成一些不必要的开销


是否有一些我忽略了的语法允许此代码在任何情况下都能正常运行?

正如我在注释中所解释的,T-SQL是一种编译语言,“无效列”是编译器错误,而不是执行错误。然而,由于大多数T-SQL只是在执行之前编译的,所以您通常会看到它

由于T-SQL尝试编译所有代码,而不考虑IF分支,因此唯一直接解决此问题的方法是使用动态SQL。像这样:

if     exists (select 1 from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'Foo' and COLUMN_NAME = 'deprecated_column')
   and exists (select 1 from [Foo] where new_column is null)
begin
    EXEC('
        declare @updated int set @updated = 1;

        while @updated > 0
        begin
            update top (500000)
                   Foo
               set new_column = deprecated_column
             where new_column is null
            ;
            set @updated = @@rowcount;
        end
    ');
end
go

@SeanLange这与您刚才所说的不符,请在IF块中输入任何有效的sql,如果控件从未进入该块,则不会出现异常。@M.Ali您是对的……删除我的注释。:(这里肯定有一个挑战。如果被引用的表不存在,代码将正确编译。但是,如果该表确实存在,那么它也会检查被引用的列是否存在。IIRC这是延迟名称解析的一部分。我认为在多个架构的情况下,您的错误是可重复的,每个架构都包含一个t。)可以命名为
Foo
。可能是这种情况吗?好吧,SQL Server检查代码是否解析,而不检查
是否满足
条件。您可以通过在
更新中使用动态SQL来解决这一问题。如
设置@SQL='UPDATE..”
,然后执行它