当前位置: 首页 > 知识库问答 >
问题:

SQL Server中的Try/Catch块不处理错误

邢璞
2023-03-14

我们在SQL Server存储过程中使用以下错误处理模式:

ALTER PROCEDURE [dbo].[USP_Districtdata_Import]
    @DistrictData DistrictData Readonly
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
    BEGIN TRAN

    --Insert the new records into BudgetDistrict Table.
    INSERT INTO [dbo].[BudgetDistrict]
    (
     DistrictID,
     [Year],
     Season,
     BudgetStateID,
     ProjectedReturnCountIsCalc,
     RowStatus,
     CreatedBy,
     CreatedDate,
     LastModifiedBy,
     LastModifiedDate,
     EnableBudgetLock
     )

    SELECT
    DISTINCT list.[District Id],list.[Year],list.[Season],1,0,'A',@CreatedBy,@Updtime,@CreatedBy,@Updtime,0
    FROM @DistrictData liston]
        AND bud.RowStatus = 'A'
        )
    LEFT OUTER JOIN [dbo].[BudgetDistrict] bud
      ON (bud.DistrictID  = list.[District Id]
        AND bud.[Year]    = list.[Year]
        AND bud.[Season]  = list.[Seas
    WHERE bud.DistrictID IS NULL


    --Update the existing pending budgets
    UPDATE wk
    SET  wk.Budget         = list.[Budget], 
         wk.BudgetAdjusted = list.[Budget],
         wk.ProjectedReturnCount = list.[ProjectedReturn Count], 
         wk.CreatedBy      = @CreatedBy, 
         wk.CreatedDate    = @Updtime,
         wk.LastModifiedBy = @CreatedBy, 
         wk.LastModifiedDate = @Updtime  
    FROM @DistrictData list
    INNER JOIN [dbo].[BudgetDistrict] bud
      ON (bud.DistrictID  = list.[District Id]
        AND bud.[Year]    = list.[Year]
        AND bud.[Season]  = list.[Season])
    INNER JOIN [dbo].[BudgetDistrictWeekly] wk
      ON (wk.NationalBudgetID = bud.BudgetDistrictID
       AND wk.[WeekDate]      = list.[Week])
    WHERE bud.RowStatus  = 'A'
       AND wk.RowStatus  = 'A'
       AND bud.BudgetStateID = 1

    --Insert the new budgets
    INSERT INTO [dbo].[BudgetDistrictWeekly]
    (
    WeekDate,
    Budget,
    BudgetAdjusted,
    RowStatus,
    CreatedBy,
    CreatedDate,
    LastModifiedBy,
    LastModifiedDate,
    ProjectedReturnCount
    )

    SELECT LIST.[Week],list.[Budget],list.[Budget],'A',@CreatedBy,@Updtime,@CreatedBy,@Updtime,[ProjectedReturn Count]
    FROM @DistrictData list
    LEFT JOIN [dbo].[BudgetDistrict] bud
      ON (bud.DistrictID  = list.[District Id]
        AND bud.[Year]    = list.[year]
        AND bud.[Season]  = list.Season
        AND bud.RowStatus = 'A')
    WHERE bud.DistrictID IS NULL

       IF @@ERROR = 0
       BEGIN
              COMMIT TRAN;
      END
    END TRY
    BEGIN CATCH
        SELECT 
            ERROR_NUMBER() AS ErrorNumber,  
            ERROR_LINE() AS ErrorLine, 
            ERROR_MESSAGE() AS ErrorMessage;
        ROLLBACK TRAN;
    END CATCH

SET NOCOUNT OFF;
END

但是当存储过程中出现以下错误时,try/catch块不起作用。

错误详细信息:存储过程试图将NULL值插入非NULL列。

在执行存储过程中,我得到了以下错误

EXECUTE之后的事务计数表示BEGIN和COMMIT语句的数量不匹配。上一个计数=1,当前计数=0。

msg 3903, Level 16, State 1, Line 30
ROLLBACK TRANSACTION请求没有对应的BEGIN TRANSACTION。

为什么不处理异常?请帮忙

共有2个答案

严柏
2023-03-14

有一种方法,如果你能够使用动态sql,那么尝试捕获工作

宋耀
2023-03-14

根据留档(错误不受TRY… CATCH构造部分的影响),有些错误不会被CATCH语句捕获。

尤其:

  • 阻止批处理运行的编译错误,如语法错误
  • 语句级重新编译过程中发生的错误,如编译后由于延迟名称解析而发生的对象名称解析错误

非常典型的情况是,存储过程访问在创建存储过程后删除的表列(或访问对象)。

请参见下面的示例:

create table #test (id int, somecolumn uniqueidentifier)
GO
create procedure #testSP
as
begin try
    set nocount on;

    begin tran;

    insert into #test (id, somecolumn)
    values (1, 0x);

    commit;

end try
begin catch
    rollback;
    print 'Error happened';
end catch
GO
exec #testSP
GO
alter table #test
    drop column somecolumn
GO
exec #testSP
GO

上述代码生成

消息 207,级别 16,状态 1,过程 #testSP_..._00053EAF,第 33 行列名称“某个列”无效。

消息 266,级别 16,状态 2,过程 #testSP_..._00053EAF,执行后的第 33 行事务计数指示 BEGIN 和 COMMIT 语句的数量不匹配。上一个计数 = 1,当前计数 = 2。

如您所见,尽管严重性级别为 16,但不会捕获错误,并且不会打印消息“发生错误”。

 类似资料:
  • 这个块似乎没有捕获发生的错误,这很奇怪,考虑到我对网站的注册部分有一个类似的块。这将处理登录。该错误发生在第三行 并引发此错误: 当电子邮件格式错误时会发生这种情况,例如。因此,当它是时,我希望在块中设置错误消息。 有人知道为什么这个< code>try catch不起作用吗?

  • 不管你多么精通编程,有时我们的脚本总还是会出现错误。可能是因为我们的编写出错,或是与预期不同的用户输入,或是错误的服务端响应以及其他数千种原因。 通常,如果发生错误,脚本就会“死亡”(立即停止),并在控制台将错误打印出来。 但是有一种语法结构 try..catch,它使我们可以“捕获(catch)”错误,因此脚本可以执行更合理的操作,而不是死掉。 “try…catch” 语法 try..catch

  • 我正在尝试捕获caller方法中的IllegalAccessException。但它抓不到它。而是给出了一个错误。

  • 我需要在我的存储过程中添加错误处理。我相信当只有一个insert语句时,通常不需要使用BEGIN TRAN/COMMIT TRAN。还有使用SET XACT_ABORT,NOCOUNT ON语句的意义是什么。请给出最佳/标准的方法将错误处理添加到下面的SP中。如果出现错误,我还需要在catch段中调用dbo.usp_get_error_info。请建议。

  • 问题内容: 我最初从大学开始编程,然后学习了vb.net。现在,我决定转向Java并进行一些查询。在vb中,try catch语句的布局如下 但是在Java网站(https://docs.oracle.com/javase/tutorial/essential/exceptions/putItTogether.html)中,我发现在Java中,您使用了两个陷阱,如下所示: 我希望有人能够解释为什么

  • 这是我的脚本,它返回一个布尔值 我希望脚本打印捕获的异常,并返回布尔值,但在本例中,脚本失败时只返回false。感谢您的帮助,我需要打印异常,就像try-catch块不存在一样。