我正在处理需要删除列的数据库升级脚本(该部分很容易)。在我删除列之前,我想获取值并将其移动到另一个已存在的列中。
我正试图用我的脚本实现idempotence,这是我似乎失败的地方。我有这样的代码...
IF EXISTS (SELECT *
FROM sys.all_columns
WHERE sys.all_columns.object_id = OBJECT_ID(N'[dbo].[MyTable]')
AND sys.all_columns.name = 'Column1')
BEGIN
UPDATE [dbo].[MyTable]
SET [Column2] = [Column1]
ALTER TABLE [dbo].[MyTable]
DROP COLUMN [Column1]
END
无论我做什么,始终执行UPDATE
查询,即使条件为false,也会导致错误。如果我的初始条件为false,我需要做什么来阻止运行此查询?如果条件为真,它下面的ALTER TABLE
语句才会运行。
答案 0 :(得分:12)
我猜测当你说“UPDATE查询总是被执行,导致错误”时,你的意思是你得到错误:
Msg 207, Level 16, State 1 Line 6
Invalid column name 'Column1'.
这不是因为查询正在执行 - 这是一个解析错误。 SQL Server在执行之前会对整个IF语句进行解析,并且在UPDATE语句中失败,因为Column1不再存在。它在ALTER TABLE语句中也失败了,但SQL Server只显示第一个错误。
顺便说一句,这就是为什么Shannon的例子有效 - 因为她的两个IF块都被立即解析,第二个类似于你的解析就好了,因为在解析脚本时,列仍然存在。我怀疑如果Shannon再次运行她的脚本(减去创建表部分),就会出现同样的错误。
要解决这个问题,您只需要使用动态SQL - 在实际运行该行之前不会对其进行解析。您使用EXEC命令运行动态SQL,并将它传递给您要执行的字符串,如下所示:
IF EXISTS (SELECT *
FROM sys.all_columns
WHERE sys.all_columns.object_id = OBJECT_ID(N'[dbo].[MyTable]')
AND sys.all_columns.name = 'Column1')
BEGIN
EXEC('UPDATE [dbo].[MyTable] SET [Column2] = [Column1]')
EXEC('ALTER TABLE [dbo].[MyTable] DROP COLUMN [Column1]')
END