【问题标题】:CATCH statement not firing in SQL script在 SQL 脚本中未触发 CATCH 语句
【发布时间】:2015-02-16 01:42:38
【问题描述】:

我正在寻找一种方法来围绕一些 SQL 脚本语句创建一个“包装器”,这些语句既可以是事务性的(提交/回滚),又可以在屏幕上为运行脚本的用户提供某种错误消息。

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

我可以在 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 transactions try-catch


    【解决方案1】:

    它不会触发捕获,因为它甚至没有达到运行任何 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个不同的结果集

    【讨论】:

    • 感谢您为我澄清这一点。我知道我没有包含正确数量的值来匹配列(我为此示例故意这样做)。在实际示例中,中间有一些表格
    • -- 我的脚本被编辑(删除了不再需要的列),它导致脚本失败(显然),但是当它没有按预期失败时(即触发 CATCH ) 我很惊讶。我现在知道编译错误和我猜想可能被认为是运行时错误之间的区别。感谢您在这方面的帮助!
    • 没问题。我已经用您可能想要考虑的内容更新了我的答案(我最初没有包括它,因为我想确认它有效:))
    • 所以如果我理解正确...当您在 TRY 中使用 exec sp_executesql 方法执行某些脚本时,它会跳转到 CATCH 用于 Compilation ErrorsRun-Time Errors 与我现在只得到 Run-Time Errors?
    • 快速第二次跟进...如果我说 150 行脚本是 4+ 个不同的谨慎步骤,我可以执行以下操作:DECLARE @ SQLText NVARCHAR(8000); SET @ SQLText = N' 我在这里的所有 4+ 步骤;执行 sp_executesql @SQLText ?我想我是在问 exec sp_executesq 是否必须是单个操作还是可以包含多个操作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多