SQL 当 IF 条件为真时,ELSE 块仍然抛出错误
SQL ELSE block still throws error when IF condition is true
我有以下 T-SQL 脚本,它将旧列的值复制到新列中,然后删除旧列。看这里:
--step 1: create new column
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn2'
AND Object_ID = Object_ID(N'Account'))
BEGIN
ALTER TABLE Account
ADD UserColumn2 int null
;
END
GO
;
--step 2: copy and drop
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account'))
BEGIN
PRINT 'Column ''UserColumn1'' does not exist.';
END
ELSE
BEGIN
UPDATE Account
SET UserColumn2 = UserColumn1
WHERE UserColumn1 is not null
;
BEGIN TRY
Declare @count int;
SELECT @count = Count(AccountID)
FROM Account
WHERE UserColumn2 <> UserColumn1
;
IF @count > 0
BEGIN
--PRINT 'Not all records were properly updated. UserColumn1 has not been dropped.';
THROW 50000,'Not all records were properly updated. UserColumn1 has not been dropped.',1
;
END
ELSE
BEGIN
ALTER TABLE Account
DROP Column UserColumn1
;
END
END TRY
BEGIN CATCH THROW; END CATCH
END
GO
;
第一步运行正确,但第二步仍然在 ELSE
块中抛出错误,即使 UserColumn1
列不存在也是如此:
(注意:这里的代码实际上在第 24 行抛出。我的 SSMS 中的代码没有 'step 1' 等的注释)
为什么会发生这种情况,我该如何预防?
我尝试删除 NOT
并将指令移出 ELSE
块,但行为没有改变。我也试过这样写第二步的开头:
IF (SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account')) <> null
我得到了相同的结果。
问题是整个 sql 文本在执行之前被解析和编译,在编译时抛出错误。
您可以通过使用动态 sql 在其自己的进程中执行更新语句来解决它 - 尽管此用法中没有任何 dynamic,它只是推迟了编译并执行 update
语句,它只在您的 else
条件下发生:
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account'))
BEGIN
PRINT 'Column ''UserColumn1'' does not exist.';
END
ELSE
BEGIN
EXEC sp_executesql N'
UPDATE Account
SET UserColumn2 = UserColumn1
WHERE UserColumn1 is not null;'
...
...
我有以下 T-SQL 脚本,它将旧列的值复制到新列中,然后删除旧列。看这里:
--step 1: create new column
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn2'
AND Object_ID = Object_ID(N'Account'))
BEGIN
ALTER TABLE Account
ADD UserColumn2 int null
;
END
GO
;
--step 2: copy and drop
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account'))
BEGIN
PRINT 'Column ''UserColumn1'' does not exist.';
END
ELSE
BEGIN
UPDATE Account
SET UserColumn2 = UserColumn1
WHERE UserColumn1 is not null
;
BEGIN TRY
Declare @count int;
SELECT @count = Count(AccountID)
FROM Account
WHERE UserColumn2 <> UserColumn1
;
IF @count > 0
BEGIN
--PRINT 'Not all records were properly updated. UserColumn1 has not been dropped.';
THROW 50000,'Not all records were properly updated. UserColumn1 has not been dropped.',1
;
END
ELSE
BEGIN
ALTER TABLE Account
DROP Column UserColumn1
;
END
END TRY
BEGIN CATCH THROW; END CATCH
END
GO
;
第一步运行正确,但第二步仍然在 ELSE
块中抛出错误,即使 UserColumn1
列不存在也是如此:
(注意:这里的代码实际上在第 24 行抛出。我的 SSMS 中的代码没有 'step 1' 等的注释)
为什么会发生这种情况,我该如何预防?
我尝试删除 NOT
并将指令移出 ELSE
块,但行为没有改变。我也试过这样写第二步的开头:
IF (SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account')) <> null
我得到了相同的结果。
问题是整个 sql 文本在执行之前被解析和编译,在编译时抛出错误。
您可以通过使用动态 sql 在其自己的进程中执行更新语句来解决它 - 尽管此用法中没有任何 dynamic,它只是推迟了编译并执行 update
语句,它只在您的 else
条件下发生:
IF NOT EXISTS(SELECT 1 from sys.columns
WHERE Name = N'UserColumn1'
AND Object_ID = Object_ID(N'Account'))
BEGIN
PRINT 'Column ''UserColumn1'' does not exist.';
END
ELSE
BEGIN
EXEC sp_executesql N'
UPDATE Account
SET UserColumn2 = UserColumn1
WHERE UserColumn1 is not null;'
...
...