从存储过程返回错误消息

时间:2015-10-22 09:22:01

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

问题应该很简单,但我无法弄清楚答案,也不能解释为什么我的存储过程无效。

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约束,它会遇到错误(这很好),我想抓住错误。

  

Msg 547,Level 16,State 0,Procedure spTest_Delete,Line 12
  DELETE语句与REFERENCE约束冲突   “FK_TEstFK_Test”。冲突发生在数据库“Test”,表中   “dbo.Test”,列'ID'。该语句已终止。

     

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

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

2 个答案:

答案 0 :(得分:5)

您可能希望在程序中使用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总是为空?因为ERROR_MESSAGE()仅在CATCH块中有效。这是用documentation写的:

  

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

Using TRY..CATCH in Transact-SQL告诉我们:

  

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

答案 1 :(得分:3)

尝试使用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