これが今の私のコードです:
BEGIN TRY
INSERT INTO TABLE (F1,F2,F3)
VALUES ('1','2','3')
END TRY
BEGIN CATCH
;THROW
END CATCH
SQL 2008が搭載されたマシンで実行しない限り、うまく機能します。CATCHブロックでSQLバージョンをチェックし、それが2012以上の場合はTHROWを実行し、2008の場合はRAISERRORを実行します。構文エラー、それが可能かどうか疑問に思っています。このような単純なものでさえ、私にはうまくいきません。
BEGIN CATCH
IF ((SELECT SERVERPROPERTY('productversion')) >= 11) ;THROW
END CATCH
任意のアドバイスをいただければ幸いです。
いいえ、これは不可能です。
これは以前のバージョンでは無効な構文であり、コンパイルエラーの原因になります。
パラメータなしのスローをキャッチ内に直接含める必要があるため、キャッチブロック内のTHROW
内のEXEC
を非表示にすることもできません。
展開先のSQL Serverのバージョンに応じて、必要なコードバージョンを展開する必要があります(残念ながら、私が認識しているSSDTツールでは、これに対する適切なサポートはありません。コード行を選択的に含めることに相当するものはありません。条件付きコンパイル)
たとえTHROW
とRAISERROR
を交互に切り替えることが技術的に可能であったとしても、あなたが(おそらく)実際にこれを実行したくないことを指摘しておく必要があります。どうして?パラメータレスTHROW
の非常に気の利いた機能は、同じメッセージ番号(つまり、Msg 8134
Msg X
の代わりにX
> = 50000)はそれらの間の唯一の違いではありません。THROW
はバッチ中止されますが、RAISERROR
はそうではありません。以下に示すように、これは重要な動作の違いになる可能性があります。
テスト設定
--DROP PROC ##Throw;
--DROP PROC ##RaisError;
GO
CREATE PROCEDURE ##Throw
AS
SET NOCOUNT ON;
BEGIN TRY
SELECT 1/0 AS [DivideByZero];
END TRY
BEGIN CATCH
THROW;
END CATCH;
SELECT 1 AS [AA];
GO
CREATE PROCEDURE ##RaisError
AS
SET NOCOUNT ON;
BEGIN TRY
SELECT 1/0 AS [DivideByZero];
END TRY
BEGIN CATCH
RAISERROR('test, yo!', 16, 1);
-- RETURN; -- typically at end of CATCH block when using RAISERROR
END CATCH;
SELECT 2 AS [BB];
GO
テスト1
EXEC ##Throw;
SELECT 3 AS [CC];
戻り値:
"Results" Tab:
DivideByZero
{empty result set}
"Messages" Tab:
Msg 8134, Level 16, State 1, Procedure ##Throw, Line 38
Divide by zero error encountered.
テスト2
EXEC ##RaisError;
SELECT 4 AS [DD];
戻り値:
"Results" Tab:
DivideByZero
{empty result set}
BB
2
DD
4
"Messages" Tab:
Msg 50000, Level 16, State 1, Procedure ##RaisError, Line 45
test, yo!
公平を期すために、次のようにしてこの違いを隠すことができます。
THROW
を使用してコードへのすべての呼び出しをTRY...CATCH
構成内にラップします(以下に示します)THROW
の後にコードを配置しない(まあ、END CATCH;
を除く)テスト
BEGIN TRY
EXEC ##Throw;
SELECT 5 AS [EE];
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS [ErrorNumber], ERROR_MESSAGE() AS [ErrorMessage];
END CATCH;
SELECT 6 AS [FF];
GO
戻り値:
"Results" Tab:
DivideByZero
{empty result set}
ErrorNumber ErrorMessage
8134 Divide by zero error encountered.
FF
6
テスト4
BEGIN TRY
EXEC ##RaisError;
SELECT 7 AS [GG];
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS [ErrorNumber], ERROR_MESSAGE() AS [ErrorMessage];
END CATCH;
SELECT 8 AS [HH];
GO
戻り値:
"Results" Tab:
DivideByZero
{empty result set}
ErrorNumber ErrorMessage
50000 test, yo!
HH
8
私は Martin Smithの答え がほぼ100%正しいと信じています。
これを行う唯一の方法は動的SQLを使用することであり、すべてのtry/catchブロック(または、2つのバージョンのそれら)は、バージョンに応じて実行されます。
それを維持するのは悪夢です。しないでください。