我遇到了一个奇怪的问题。代码:
if not exists(select * from sys.columns where Name = N'columnName' and Object_ID = Object_ID(N'[xxx].[yyy]'))
BEGIN
ALTER TABLE [xxx].[yyy] ADD [columnName] [bit] NOT NULL Default 0
update [xxx].[yyy] set [columnName] = 1
END
此SQL文件片段失败,并显示错误,指出列[columnName]
不存在于update语句中。在SSMS中执行ALTER TABLE
行时,它会正确执行,然后程序正常工作。可能是这个问题的根源?
答案 0 :(得分:2)
最简单的方法是将其拆分为单独的批次。另外,让ALTER
在EXEC
内运行,否则当 列存在时,您可能会遇到问题:
if not exists(select * from sys.columns where Name = N'columnName' and
Object_ID = Object_ID(N'[xxx].[yyy]'))
BEGIN
exec('ALTER TABLE [xxx].[yyy] ADD [columnName] [bit] NOT NULL Default 0')
END
GO
update [xxx].[yyy] set [columnName] = 1
问题是(简单化)T-SQL编译器尝试一次编译整个批次(批次由GO
1 s分隔)。所以它甚至在它开始执行任何逻辑之前都试图编译UPDATE
。
使其成为条件:
if not exists(select * from sys.columns where Name = N'columnName' and
Object_ID = Object_ID(N'[xxx].[yyy]'))
BEGIN
exec('ALTER TABLE [xxx].[yyy] ADD [columnName] [bit] NOT NULL Default 0')
exec('update [xxx].[yyy] set [columnName] = 1')
END
我们有效地使用exec
再次延迟编译,直到我们知道我们希望它发生。
顺便提一下,在这种情况下,我可能会采取第三种方式:
if not exists(select * from sys.columns where Name = N'columnName' and
Object_ID = Object_ID(N'[xxx].[yyy]'))
BEGIN
exec('ALTER TABLE [xxx].[yyy] ADD [columnName] [bit] NOT NULL constraint DF_XXX Default 1')
exec('ALTER TABLE xxx.yyy DROP CONSTRAINT DF_XXX')
exec('ALTER TABLE xxx.yyy ADD CONSTRAINT DF_XXX DEFAULT (0) FOR columnName')
END
因为前两个方法将首先更新整个表以使该列中包含0
,然后然后再次更新表以将值设置为1
- 而这个最终方法应该只需要更新一次现有的行。
1 批次由客户端工具(例如SSMS)而不是SQL Server拆分。 GO
不是SQL Server语句/命令,而且令人担忧的是,这些工具只使用默认批处理分隔符。它可能会从默认值更改为其他内容,但我确实建议不要使用它。