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个不同的结果集
我一直在寻找一种方法来围绕一些 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个不同的结果集