【问题标题】:Return error message from stored procedure从存储过程返回错误消息
【发布时间】:2016-01-21 12:38:23
【问题描述】:

问题应该很简单,但我不知道答案,也不知道为什么我的存储过程不工作。

CREATE PROCEDURE spTest_Delete
@ID int
AS
    begin tran
        declare @err int
        declare @errMesage nvarchar(max)
        set @errMesage = ''
        set @err = 0

        delete from Test
        where ID = @ID

        set @err = @@ERROR
        set @errMesage = ERROR_MESSAGE()

        if @err = 0 
           commit tran
        else 
        begin
            RAISERROR(N'Could not delete !Error nr: %d. Message: %s', 1, 16, @err, @errMesage)
            rollback tran
        end

此过程运行正常,但在 delete 语句上存在 FK 约束的情况下,它会遇到错误(这很好),我想捕获该错误。

消息 547,级别 16,状态 0,过程 spTest_Delete,第 12 行
DELETE 语句与 REFERENCE 约束冲突 “FK_TEstFK_Test”。数据库“Test”中发生冲突,表 “dbo.Test”,“ID”列。该语句已终止。

无法删除!
错误编号:547。消息:(空)消息 50000,级别 1,状态 16

我的消息变量总是为 null,即使 delete 语句引发错误。

【问题讨论】:

    标签: sql-server stored-procedures sql-server-2012


    【解决方案1】:

    尝试使用 TRY CATCH 并像这样捕获您的错误:

    BEGIN TRY
       delete from Test
        where  ID = @ID
    END TRY
    BEGIN CATCH
        SET @ErrorMessage  = ERROR_MESSAGE()
        SET @ErrorSeverity = ERROR_SEVERITY()
        SET @ErrorState    = ERROR_STATE()
        RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
        BREAK
    END CATCH
    

    【讨论】:

    • Try catch 成功了,但我还是有点困惑,为什么没有 try catch 就不行。
    • @CiucaS:- 通常建议使用 TRY..CATCH 来捕获错误。你可以尝试使用if ISNULL(@err,0) = 0
    • .net端如何捕获ErrorMessage?
    • 我看到RaiseError 将返回(通过.NET 异常)它的msg_str 参数如果调用者是.NET 应用程序,但它如何返回它,如果调用者是另一个存储过程? Error_Message(以及所有 Error_* 函数)在 Exec 之后立即返回 Null,该存储过程在它之前调用 RaiseError return-ed 并且它也不会触发 Catch在调用存储过程中阻塞。
    • @Tom 我很想知道你的评论的答案
    【解决方案2】:

    您可能希望开始在您的程序中使用TRY..CATCH

    为 Transact-SQL 实现错误处理,类似于 Microsoft Visual C# 和 Microsoft Visual C++ 中的异常处理 语言。一组 Transact-SQL 语句可以包含在 TRY 中 堵塞。如果 TRY 块中发生错误,则将控制权传递给 包含在 CATCH 块中的另一组语句。

    所以你的程序可以重写为:

    CREATE PROCEDURE spTest_Delete @ID INT
    AS
    BEGIN
        SET NOCOUNT ON;
        BEGIN TRY
            BEGIN TRANSACTION
                DELETE
                FROM Test
                WHERE ID = @ID;
            COMMIT TRANSACTION
        END TRY
        BEGIN CATCH
            IF @@TRANCOUNT > 0
                ROLLBACK TRANSACTION
            SELECT ERROR_NUMBER(), ERROR_MESSAGE();
        END CATCH
    END
    

    另外,请注意您是作为单个删除语句运行的。这意味着它不需要包含在事务中。 This 问题解释了原因。

    你的代码变成这样:

    CREATE PROCEDURE spTest_Delete @ID INT
    AS
    BEGIN
        SET NOCOUNT ON;
        BEGIN TRY
            DELETE
            FROM Test
            WHERE ID = @ID;
        END TRY
        BEGIN CATCH
            SELECT ERROR_NUMBER(), ERROR_MESSAGE();
        END CATCH
    END
    

    现在为什么你的@errMessage 总是为NULL?因为ERROR_MESSAGE() 仅在捕获块中有效。写在documentation:

    返回导致 CATCH 块的错误的消息文本 TRY…CATCH 构造被运行。

    Using TRY..CATCH in Transact-SQL 告诉这个:

    使用这些函数从任何地方检索错误信息 在 TRY…CATCH 构造的 CATCH 块的范围内。 错误 如果在 CATCH 范围之外调用,函数将返回 NULL 阻止

    【讨论】:

      猜你喜欢
      • 2012-01-25
      • 2020-05-01
      • 2021-08-14
      • 1970-01-01
      • 2020-07-14
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多