的問題是proc子調用MyInnerError
沒有失敗;在MyInnerError
內的呼叫失敗,但MyInnerError
已完全成功。
MyInnerError
正在成功完成,因爲您沒有陷入錯誤並報告失敗,就像您在外部過程中通過TRY
/CATCH
結構所做的那樣。
這和來自動態SQL的錯誤自然不會設置ERROR_PROCEDURE()
。
您所有的特效應具有TRY
/CATCH
結構和CATCH
塊應該使用RAISERROR或擲(取決於你使用的是什麼版本的SQL Server),這樣你可以泡錯誤到呼叫範圍。
DECLARE @InNestedTransaction BIT = 0;
BEGIN TRY
IF (@@TRANCOUNT > 0)
BEGIN
SET @InNestedTransaction = 1;
END;
ELSE
BEGIN
BEGIN TRAN;
END;
... one or more SQL statements ...
COMMIT;
END TRY
BEGIN CATCH
IF (@InNestedTransaction = 0)
BEGIN
ROLLBACK;
END;
IF (ERROR_PROCEDURE() IS NULL)
BEGIN
DECLARE @ErrMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrState TINYINT = ERROR_STATE(),
@ErrSeverity TINYINT = ERROR_SEVERITY();
RAISERROR(@ErrMessage, @ErrSeverity, @ErrState);
RETURN;
END;
;THROW; -- introduced in SQL Server 2012
---- If using SQL Server 2008, replace the above (from "IF" through "THROW")
---- with the following.
-- DECLARE @ErrMessage NVARCHAR(4000) = ERROR_MESSAGE();
-- RAISERROR(@ErrMessage, 16, 1);
-- RETURN;
END CATCH;
的IF (ERROR_PROCEDURE() IS NULL)
塊被用來捕捉這樣的情況,其中沒有PROC產生誤差。調用;THROW;
本身會引起當前錯誤信息,在本例中爲NULL
爲ERROR_PROCEDURE()
。
如果你想這個測試自己,只需要運行下面的SQL它創建3個存儲過程,所有這些都使用上面所示的結構。最內層的程序(ErrorTest1)使用SELECT 1/0;
作爲查詢調用sp_executesql
。 「除以零」錯誤被TRY/CATCH捕獲。 ERROR_PROCEDURE()
函數返回NULL
,因爲它是生成錯誤的動態SQL。因此,調用RAISERROR
(技術上調用;THROW 50505, @ErrMessage, @ErrState;
也可以)以向調用進程指示當前proc生成錯誤。
測試設置:
IF (OBJECT_ID(N'ErrorTest3') IS NOT NULL)
BEGIN
DROP PROCEDURE ErrorTest3;
END;
IF (OBJECT_ID(N'ErrorTest2') IS NOT NULL)
BEGIN
DROP PROCEDURE ErrorTest2;
END;
IF (OBJECT_ID(N'ErrorTest1') IS NOT NULL)
BEGIN
DROP PROCEDURE ErrorTest1;
END;
GO
CREATE PROCEDURE dbo.ErrorTest1
AS
SET NOCOUNT ON;
DECLARE @InNestedTransaction BIT = 0;
BEGIN TRY
IF (@@TRANCOUNT > 0)
BEGIN
SET @InNestedTransaction = 1;
END;
ELSE
BEGIN
BEGIN TRAN;
END;
SELECT '1a';
EXEC sp_executesql N'SELECT 1/0 AS [ForceError];';
SELECT '1b';
COMMIT;
END TRY
BEGIN CATCH
IF (@InNestedTransaction = 0)
BEGIN
ROLLBACK;
END;
IF (ERROR_PROCEDURE() IS NULL)
BEGIN
DECLARE @ErrMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrState TINYINT = ERROR_STATE(),
@ErrSeverity TINYINT = ERROR_SEVERITY();
RAISERROR(@ErrMessage, @ErrSeverity, @ErrState);
RETURN;
END;
;THROW; -- introduced in SQL Server 2012
END CATCH;
GO
CREATE PROCEDURE dbo.ErrorTest2
AS
SET NOCOUNT ON;
DECLARE @InNestedTransaction BIT = 0;
BEGIN TRY
IF (@@TRANCOUNT > 0)
BEGIN
SET @InNestedTransaction = 1;
END;
ELSE
BEGIN
BEGIN TRAN;
END;
SELECT '2a';
EXEC dbo.ErrorTest1;
SELECT '2b';
COMMIT;
END TRY
BEGIN CATCH
IF (@InNestedTransaction = 0)
BEGIN
ROLLBACK;
END;
IF (ERROR_PROCEDURE() IS NULL)
BEGIN
DECLARE @ErrMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrState TINYINT = ERROR_STATE(),
@ErrSeverity TINYINT = ERROR_SEVERITY();
RAISERROR(@ErrMessage, @ErrSeverity, @ErrState);
RETURN;
END;
;THROW; -- introduced in SQL Server 2012
END CATCH;
GO
CREATE PROCEDURE dbo.ErrorTest3
AS
SET NOCOUNT ON;
DECLARE @InNestedTransaction BIT = 0;
BEGIN TRY
IF (@@TRANCOUNT > 0)
BEGIN
SET @InNestedTransaction = 1;
END;
ELSE
BEGIN
BEGIN TRAN;
END;
SELECT '3a';
EXEC dbo.ErrorTest2;
SELECT '3b';
COMMIT;
END TRY
BEGIN CATCH
IF (@InNestedTransaction = 0)
BEGIN
ROLLBACK;
END;
SELECT ERROR_PROCEDURE() AS [ErrorProcedure],
ERROR_STATE() AS [ErrorState],
ERROR_SEVERITY() AS [ErrorSeverity];
IF (ERROR_PROCEDURE() IS NULL)
BEGIN
DECLARE @ErrMessage NVARCHAR(4000) = ERROR_MESSAGE(),
@ErrState TINYINT = ERROR_STATE(),
@ErrSeverity TINYINT = ERROR_SEVERITY();
RAISERROR(@ErrMessage, @ErrSeverity, @ErrState);
RETURN;
END;
;THROW; -- introduced in SQL Server 2012
END CATCH;
GO
運行測試:
EXEC dbo.ErrorTest3;
返回:
5的結果集:
3a
2a
1a
<empty>
ErrorProcedure ErrorState ErrorSeverity
ErrorTest1 1 16
並在 「信息」 選項卡:
消息50000,級別16,狀態1,過程ErrorTest1,行36
除以零錯誤遇到。
https://sqlserverrider.wordpress.com/2013/09/12/sql-server-get-the-failed-stored-procedure-name-using-error_procedure/ – mohan111 2015-02-10 12:49:38
這就是我比做什麼,但它被設置爲NULL,我正在調用sproc中的sproc。 – davey 2015-02-10 12:53:25