CATCH 语句未在 SQL 脚本中触发

CATCH statement not firing in SQL script

我一直在寻找一种方法来围绕一些 SQL 脚本语句创建一个 "wrapper",这些语句既是事务性的(提交/回滚)又会向屏幕提供某种错误消息用户 运行 脚本。

在另一个问题中,我发布了我发现看起来不错的解决方案...

我可以在 TRY 内进行交易,如果出现任何错误,它应该转到 CATCH 并允许我向用户发送消息。

今天我有一个 INSERT 失败,它没有转移到 CATCH 它只是给了我一个错误(INSERT 语句中的列多于 VALUES 子句中指定的值。数字VALUES 子句中的值必须与 INSERT 语句中指定的列数匹配。)

有人可以帮助我了解发生了什么以及为什么它没有触发 CATCH 吗?

这是完整的代码...

USE master;

-- Hide Record Counts
SET NOCOUNT ON;

-- Wrap Everything in a TRY -If we get any error it will jump to CATCH and stop executing the script
BEGIN TRY;

-- Start TRANSACTION within the TRY
BEGIN TRANSACTION;

print('');
print('========= Step XX ==> START');
Print('');
Print('(( Some Action XXXX ))');
print('');

Create table #TempTest (
field1 varchar(10) null,
field2 varchar(10) null,
field3 varchar(10) null);

-- I will try to insert only 2 of the 3 columns so that I can trigger an error
-- Why does this not kick over to the CATCH?
INSERT INTO #TempTest (field1, field2, field3)
VALUES ('value1','value2');


-- COMMIT Transaction - If we had encountered an error it would have jumped to the CATCH block
COMMIT;

print('');
print('========= Step XX ==> FINISHED');
Print('');

-- End the TRY wrapper
END TRY

-- Here is the CATCH if we have any errors in the TRY section this will execute
BEGIN CATCH
    -- We need to make sure something actually happened that can be ROLLBACK
    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK;
        print('');
        print('>>>>>>>>>>>>>>>>>>>>>>>   Opps we ran into some kind of ERROR.   <<<<<<<<<<<<<<<<<<<<<<');
        print('');
    END;
END CATCH;

-- Reset the NOCOUNT to Off
SET NOCOUNT OFF;

它不会触发捕捉,因为它还没有达到甚至 运行宁你的任何 SQL 的地步。编译阶段正确地确定您的 SQL 无效 - 特别是这部分

INSERT INTO #TempTest (field1, field2, field3)
VALUES ('value1','value2');

如果更新为

INSERT INTO #TempTest (field1, field2)
VALUES ('value1','value2');

INSERT INTO #TempTest (field1, field2, field3)
VALUES ('value1','value2', 'value3');

它将通过编译并实际尝试 运行 SQL 代码。如果在此期间遇到问题,比如插入失败,因为主键已经存在,你的 catch 语句将被触发。

如果您需要能够注销编译失败的消息,您可以考虑 sp_executesql

begin try
  declare @Statement nvarchar(max) = N'I am bad syntax'
  exec sp_executesql @statement = @Statement
end try
begin catch
  print 'Here'
  print ERROR_MESSAGE()
end catch

要在 sp_executesql 中执行多个语句,您可以生成一个包含所有需求语句的字符串。您可以使用 ;如果您将它们全部生成为一行,则将它们分开:

begin try
  declare @Statement nvarchar(max) = 'select 1;select 2;select 3'
  exec sp_executesql @statement = @Statement
end try
begin catch
  print 'Here'
  print ERROR_MESSAGE()
end catch

以上会生成3个不同的结果集