"列名无效"抛出无法访问的脚本块

时间:2015-11-05 20:37:33

标签: sql-server tsql sql-server-2012

我设计了一个大型的sql脚本,因此它是安全的。在不同实例上运行,或在同一实例上多次运行而不会导致任何错误数据或错误

编写这样的脚本时,我总是依赖于语法:

from datetime import datetime
from datetime import timedelta

movies = [
"13:00 Alien Beetroot",
"15:30 Bananas Go Bad!",
"17:45 Cheerleader Lake",
"19:00 Yoghurt Spoon Eater",
"21:10 Zombie A Go-Go",
"23:30 Shark Snacks VI",
"02:15 Drive-In Dinosaur Disaster"
]

myTime = "18:30"
myDate = "Wed 03 November 2015"
cineDate = "Wed 03 November 2015" 
t = datetime.strptime(myDate + " " + myTime, "%a %d %B %Y %H:%M")

for i in range(0, len(movies)):
  sp = movies[i].split(" ", 1)
  tim = sp[0]
  mov = sp[1]
  show = datetime.strptime(cineDate + " " + tim, "%a %d %B %Y %H:%M")

  if show.time() >= t.time():
    print tim + " " + mov

这通常效果很好。但是,我最近遇到了一种情况,我无法阻止在执行期间抛出错误。在下面的代码中,列" deprecated_column"已经从表Foo中删除了:

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

如果我独立于此计划在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 内运行两个exist,则会返回"没有结果"正如所料,这意味着永远不会执行内部代码。但是,当我运行脚本时,服务器会抛出错误:if,并且脚本被标记为带有错误的完成,这会导致在我们的系统上引发警报(即,DBA会收到通知并且必须check),这会导致一些简单的自动化任务产生一些不必要的开销。

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

1 个答案:

答案 0 :(得分:2)

正如我在评论中解释的那样,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