Try catchと動的SQLを使用するストアドプロシージャ内でバックアップコマンドを発行する場合、バックアップコマンドを直接実行する場合と比較すると、エラーメッセージは非常に一般的です。
SP内で試行/キャッチ:
begin try
execute sp_executesql @sql; -- a backup command
end try
begin catch
print ERROR_MESSAGE(); -- save to log, etc.
end catch
結果
50000:usp_Backup:117:BACKUP DATABASEが異常終了しています。
rawコマンドを発行するwheareas:
backup DATABASE someDb to disk...
より詳細な結果:
ルックアップエラー-SQL Serverデータベースエラー:ファイル "H:\ FolderName\Filename.bak:" 112で回復不可能なI/Oエラーが発生しました(ディスクに十分なスペースがありません。).
これらの詳細をストアドプロシージャ内の変数にキャッチする方法はありますか(ログを記録し、呼び出し元に戻し、再試行ロジックのために)?詳細はメッセージチャネルで送信されているようですが、SP内で利用できるようにしたいと思います。
BACKUP DATABASE
がエラーを生成すると、実際には2つ生成されます。残念ながら、TRY/CATCH
は最初のエラーをキャプチャできません。 2番目のエラーのみをキャプチャします。
バックアップが失敗した本当の理由をキャプチャする最善の策は、バックアップを自動化することです [〜#〜] sqlcmd [〜#〜] (-o
を使用して出力をファイル)、SSIS、C#、PowerShellなど。これらすべてを使用すると、エラーのキャプチャallを大幅に制御できます。
SOコメントの回答はDBCC OUTPUTBUFFER
の使用を提案しています-可能ですが、これは子供の遊びのようには見えません。自由に楽しんでください この手順Erland Sommarskogのサイト ですが、これはTRY/CATCH
と組み合わせてもまだうまく機能しないようです。
spGET_LastErrorMessage
を使用してエラーメッセージをキャプチャできるように思われた唯一の方法は、実際のエラーがスローされた場合です。 TRY/CATCH
でラップすると、エラーが飲み込まれ、ストアドプロシージャは何もしません。
BEGIN TRY
EXEC sp_executesql N'backup that fails...';
END TRY
BEGIN CATCH
EXEC dbo.spGet_LastErrorMessage;
END CATCH
SQL Server <2012では、エラーを自分で再発生させることはできませんが、SQL Server 2012以降では可能です。したがって、次の2つのバリエーションが機能します。
CREATE PROCEDURE dbo.dothebackup
AS
BEGIN
SET NOCOUNT ON;
EXEC sp_executesql N'backup that fails...';
END
GO
EXEC dbo.dothebackup;
EXEC dbo.spGET_LastErrorMessage;
または2012年以降、これは機能しますが、元のエラーがまだスローされるため、TRY/CATCH
の目的を大幅に無効にします。
CREATE PROCEDURE dbo.dothebackup2
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
EXEC sp_executesql N'backup that fails...';
END TRY
BEGIN CATCH
THROW;
END CATCH
END
GO
EXEC dbo.dothebackup2;
EXEC dbo.spGET_LastErrorMessage;
これらのどちらの場合でも、もちろん、エラーはクライアントにスローされます。そのため、それを回避するためにTRY/CATCH
を使用している場合は、考えていない抜け穴がない限り、ユーザーにエラーを与えて、それに関する詳細をキャプチャしたり、エラーと実際の理由の両方を抑制したりできます。
まあ、これは古いスレッドであり、私が提案しようとしているのは複雑なハックであることはわかっていますが、誰かを助けることができる場合に備えて、これらのバックアップエラーがログに記録されるため、catchでxp_readerrorlogを使用できますブロックして関連メッセージ(エラーまたは情報)のログを取得します。 xp_readerrorlog paramsを探し回ることができますが、簡単に言うと、この場合に役立つ検索文字列と開始時間フィルターを指定できます。これが再試行ロジックに役立つかどうかはわかりませんが、ログの情報またはエラーをキャプチャするために、私はこのようなものを思いつきました...
IF OBJECT_ID('tempdb.dbo.#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (LogDate datetime,ProcessInfo nvarchar(100),LogText nvarchar(4000))
BEGIN TRY
SELECT @begintime = GETDATE()
EXEC sp_executesql @SQL --your backup statement string
INSERT #Results
EXEC xp_readerrorlog 0, 1, N'backed up',@databasename,@begintime
SELECT @result = LogText from #Results where ProcessInfo = 'Backup' order by logdate desc
END TRY
BEGIN CATCH
INSERT #Results
EXEC xp_readerrorlog 0, 1, N'Backup',@databasename,@begintime
SELECT @result = LogText from #Results where ProcessInfo = 'spid'+cast(@@SPID as varchar(6)) order by logdate desc
END CATCH
PRINT @result
HTH
エラーの詳細をテーブルに記録できます。ログファイルを作成することもできますが、そのためにはCLRまたはxp_cmdshellが必要になる場合があります。データベースメールを送信することもできますが、これはスパムの問題を引き起こす可能性があり、適切なログではありません。
表は最も単純です。
以下のリンクで提供されているJeremy Kadlecの例をご覧ください。