私はマスターストアドプロシージャを完了まで実行することを試みています。マスターSPは子SPを呼び出して、互いに独立したモジュラータスクを実行します(つまり、1つが失敗した場合、他の実行を停止するべきではありません。これらの子SPの1つは失敗する可能性があり、なぜ失敗するのかは事前にわかりませんが、私が遭遇した1つのシナリオは、存在しないテーブルから選択しようとしていることです。そのエラーをログに記録してから、マスタースクリプトを続行します。存在しないテーブルからの選択は端末エラーであると思います。端末エラーでも続行する方法があるかどうか知りたいのですが。
(はい、私は情報スキーマに問い合わせてテーブルの存在を判断できることを知っていますが、防御的にコード化されていないエラーをキャッチしようとしています-今日はテーブルが欠落している可能性があり、明日は可能性がありますマスタースクリプトを悲鳴を上げる停止とする、私たちが考慮していない他の何かになります。)
コード例:
DROP TABLE IF EXISTS my_error_log;
CREATE TABLE my_error_log (
error_time DATETIME,
error_msg VARCHAR(MAX)
);
GO
CREATE OR ALTER PROCEDURE failProc
AS
BEGIN
BEGIN TRY
-- This one fails, is caught, and continues...
-- SELECT 1/0;
-- This one fails, is caught, and terminates the master script...
SELECT * FROM non_existent_table;
END TRY
BEGIN CATCH
INSERT INTO my_error_log
SELECT CURRENT_TIMESTAMP, ERROR_MESSAGE();
END CATCH
END;
GO
CREATE OR ALTER PROCEDURE masterFailProc
AS
BEGIN
SET XACT_ABORT OFF;
BEGIN TRY
INSERT INTO my_error_log SELECT CURRENT_TIMESTAMP, 'start';
EXEC failProc;
EXEC failProc;
EXEC failProc;
INSERT INTO my_error_log SELECT CURRENT_TIMESTAMP, 'end';
END TRY
BEGIN CATCH
INSERT INTO my_error_log SELECT CURRENT_TIMESTAMP, 'fatal error';
END CATCH
END;
GO
EXEC masterFailProc
GO
SELECT * FROM my_error_log;
GO
DROP PROCEDURE masterFailProc;
DROP PROCEDURE failProc;
DROP TABLE my_error_log;
期待したほどエレガントではない解決策を見つけましたが、うまくいきました。誰かがもっと良いものがあれば聞いてみたいです。
masterFailProc
の問題は、個々のEXEC
呼び出しではなく、スクリプト全体をTRY..CATCH
ブロックでラップしていることです。定義が以下のように変更された場合、スクリプト全体を終了するのではなく、execごとにエラーをログに記録します。
CREATE OR ALTER PROCEDURE masterFailProc
AS
BEGIN
SET XACT_ABORT OFF;
BEGIN TRY
INSERT INTO my_error_log SELECT CURRENT_TIMESTAMP, 'start';
BEGIN TRY EXEC failProc; END TRY BEGIN CATCH /* log error */ END CATCH;
BEGIN TRY EXEC failProc; END TRY BEGIN CATCH /* log error */ END CATCH;
BEGIN TRY EXEC failProc; END TRY BEGIN CATCH /* log error */ END CATCH;
INSERT INTO my_error_log SELECT CURRENT_TIMESTAMP, 'end';
END TRY
BEGIN CATCH
INSERT INTO my_error_log SELECT CURRENT_TIMESTAMP, 'fatal error';
END CATCH
END;
GO