web-dev-qa-db-ja.com

TRY-CATCHブロックがUDF内で許可されないのはなぜですか?

SQL ServerがUDF内のTRY-CATCHブロックをサポートしないのはなぜですか?

主に計算や会話に使用されるスカラーUDFについて話している場合、このブロックは頻繁に使用する必要がありますが、ありません。

また、これにはどのような回避策を使用しますか?

24
Fedor Hajdu

MSSQLのUDFには、BOLが「データベースの状態の変更」と定義する副作用を与えることは許可されていません。これはかなりあいまいな説明ですが、MSSQLはデータベースの状態を変更するためにエラーを考慮しているようです。このUDFはコンパイルされません。

create function dbo.foo()
returns int
as
begin
    raiserror('Foo', 16, 1)
    return 1
end
go

エラーメッセージは次のとおりです。

メッセージ443、レベル16、状態14、プロシージャfoo、5行目関数内での副作用演算子「RAISERROR」の使用が無効です。

エラーを発生させるとデータベースの状態が変化すると考えられる場合は、エラーをトラップして処理することもおそらく同様です。それはあまり説明ではない、と私は認めます。

ただし、実際には、とにかくエラーの処理方法を発信者に決定させるのが最善の場合がよくあります。次のような関数を作成するとします。

create function dbo.divide (@x int, @y int)
returns float
as
begin
return @x / cast(@y as float)
end

アプリケーションが@yに対してゼロを渡す場合をどのように処理しますか?ゼロ除算の例外をキャッチした場合、次に何をしますか?どのアプリケーションが関数を呼び出しているのかさえわからない可能性があることを念頭に置いて、呼び出し元にとって意味のある関数からどのような値を返すことができますか?

NULLを返すことを考えるかもしれませんが、関数を使用するアプリケーション開発者は同意しますか?すべてのアプリケーションは、ゼロ除算エラーが同じ影響または重要性を持っていると見なしていますか?言うまでもなく、特定の場所のNULLは、おそらくアプリケーション開発者がまったく望まない方法で、クエリの結果を完全に変更する可能性があります。

あなたが唯一の開発者であれば、それは問題ではないかもしれませんが、より多くの人々がいるとすぐに1つになります。

14
Pondlife

おそらく、オーバーヘッドが大きすぎるためです。スカラー関数は、selectの一部として列で呼び出される可能性があるため、何千回も呼び出される可能性があります。 try/catchを許可するための妥当なオーバーヘッドがあった場合、それはひどく遅くなります。

2
cjk

回避策として、ストアドプロシージャ内でTRY/CATCHからUDFを呼び出します。

1
kevchadders

SQLServer 2012では、exec sp_your_procedure_with_try_catchを試すことができます。

実際、私のトリガーのいくつかは、1つのキーSPにロジックがあります。 SPなしでそれらのいくつかを書き直そうとするまで、UDFでtry-catchが許可されていないことを知りませんでした。

0
Ben