简体   繁体   English

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

[英]Errors are not handled by Try/Catch Block in SQL Server

We are using following error handling pattern in SQL Server stored procedures:我们在 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

but when the below error occurs in the stored procedure the try/catch block didn't work.但是当存储过程中出现以下错误时,try/catch 块不起作用。

Error details: stored Procedure tried to insert a NULL value into a not null column.错误详细信息:存储过程试图将NULL值插入到非空列中。

During the execution of the stored procedure, I got following error在执行存储过程期间,出现以下错误

Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. EXECUTE 之后的事务计数表示 BEGIN 和 COMMIT 语句的数量不匹配。 Previous count = 1, current count = 0.先前计数 = 1,当前计数 = 0。

Msg 3903, Level 16, State 1, Line 30消息 3903,级别 16,状态 1,第 30 行
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION. ROLLBACK TRANSACTION 请求没有对应的 BEGIN TRANSACTION。

Why is the exception not handled?为什么不处理异常? Please help请帮忙

According to documentation ( Errors Unaffected by a TRY…CATCH Construct section) some errors are not caught by CATCH statement.根据文档错误不受 TRY…CATCH 构造部分的影响),某些错误不会被 CATCH 语句捕获。

Particularly:特别是:

  • Compile errors, such as syntax errors, that prevent a batch from running.阻止批处理运行的编译错误,例如语法错误。
  • Errors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.语句级重编译过程中出现的错误,例如由于名称解析延迟导致编译后出现对象名称解析错误。

Quite typical situation is when a stored proc accesses table column (or accesses object) that were removed after the stored proc has been created.非常典型的情况是当存储过程访问在创建存储过程后删除的表列(或访问对象)时。

See the sample below:请参阅下面的示例:

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

The above code produces上面的代码产生

Msg 207, Level 16, State 1, Procedure #testSP_..._00053EAF, Line 33 Invalid column name 'somecolumn'.消息 207,级别 16,状态 1,过程#testSP_..._00053EAF,第 33 行无效的列名称“somecolumn”。

Msg 266, Level 16, State 2, Procedure #testSP_..._00053EAF, Line 33 Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements.消息 266,级别 16,状态 2,过程#testSP_..._00053EAF,第 33 行 EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数量不匹配。 Previous count = 1, current count = 2.先前计数 = 1,当前计数 = 2。

As you see despite the severity level is 16, the errors are not caught and message Error happened does not printed.如您所见,尽管严重性级别为 16,但未捕获Error happened并且未打印Error happened消息。

有一种方法,如果您能够使用动态 sql,那么请尝试使用 catch 工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM