2017-05-24 2 views
1

.netでSqlCommandを使用し、RAISERRORをスローするストアドプロシージャを呼び出すと、そのプロシージャで設定された出力変数を読み取ることができます。ただし、T-SQLバッチ内からそのプロシージャを呼び出すと、OUTPUTのパラメータがまったく設定されないように見えます。RAISERRORを呼び出す前に、ストアドプロシージャによってバッチセット内のOUTPUTパラメータを読み取るにはどうすればよいですか?

RAISERRORがエラーを示すときに、パラメータ@OUT_xをT-SQLの呼び出しから読み取るにはどうすればよいですか?

CREATE PROCEDURE dbo.p_x (
    @OUT_x INT OUTPUT 
) AS 
BEGIN 
    SET @OUT_x = 1; 
    SELECT 'inner ', @OUT_x; 
    RAISERROR('yo', 11, 1); 
END 
GO 

DECLARE @x INT = 0; 
SELECT 'initial', @x; 
BEGIN TRY 
    EXEC dbo.p_x @x OUTPUT; 
END TRY 
BEGIN CATCH 
    SELECT 'catch', @x; 
END CATCH 
SELECT 'end', @x; 

出力:

------- ----------- 
initial 0 


------ ----------- 
inner 1 


----- ----------- 
catch 0 


---- ----------- 
end 0 

私は@OUT_xがRAISERROR経由投げる前に、ストアドプロシージャ内でその値を示すことによって、1に設定したことを証明しました。私は "キャッチ"と "終了"のエントリが1であると予想しましたが、OUTPUTのパラメータ値のコピーは、ストアドプロシージャが正常に完了した場合にのみ発生します。 I know I can read these OUTPUT parameters when I call stored procedures through SqlCommand - T-SQLバッチはどのように異なる必要がありますか?

ストアドプロシージャの変更を伴わない回避策がありますか?私は実際に私のストアドプロシージャが例外的な状況で(RAISERROR)をスローするようにしたいが、またエラーの詳細を伝えるのにOUTPUTパラメータを使う必要がある。

+0

T-SQLバッチは違いがありません。このコードブロック全体を 'SqlCommand'を通して実行した場合、同じ結果が得られます。あなたの質問は実際に 'TRY .. CATCH'が何をしているのか(ストアドプロシージャが' RAISERROR'を行うときに出力パラメータをコピーしない)についてです。アーランドはこれをカバーしています(http:// sommarskog。se/error_handling/Part2.html#systemfunctions)を、エラーハンドリングについての彼の無敵の記事で説明していますが、基本的にはこれが動作する方法です。 'TRY .. CATCH'を使うことはできず、エラーの前に割り当てられた出力パラメータの値も取得できます。 –

+1

@ JeroenMostert 'SqlCommand'は、あなたが期待するようにパラメータに' 1'を返します。 – GSerg

+1

@binki、@GSerg:あなたができることが分かっていても、私はそれをテストしていませんが、ここでの重要な問題は、 'try {...} catch {...}' T-SQLの 'TRY ... CATCH'と同じものではありません。私は 'TRY ... CATCH'を含むコードブロック全体を' SqlCommand'として実行することについて話しています。あなたは本当に結果が違うと私に伝えていますか?明らかに、可能ならば* T-SQLの外で*エラーを処理することができます。しかし、私はここでオプションではないことを正確に質問から集まります。 –

答えて

4

RAISERRORブロックが入力され、CATCHブロックが入力されたときに出力パラメータの値が適切なローカル変数にコピーされません。これは、TRY .. CATCHの動作の制限です。これには何かがあります(結局のところ、エラーが発生したため、結果は信頼されていない可能性が高いですが)。まず、ストアドプロシージャがそれまでに生成した結果セットを無視する試みはありません(結果を1つの可能な回避策がありますが、ストアドプロシージャを変更する必要があります)。私が知る限り、この動作はT-SQLのエラー処理を含む多くのものがそうではないので、正式には文書化されていませんが、Erland Sommarskogのexcellent articleに言及しています。

クライアントコードは、結果が通信される方法のために同じ問題を抱えません。出力パラメータが割り当てられている場合、TDSパケットはそれを示すために戻されます。エラーが発生すると、それを示す別のTDSパケットが戻されます。これらは時系列で起こります。クライアントはをアクティブに廃棄する必要があります。エラーの出力パラメータは、コピーすることを忘れずに、TRY .. CATCHと同じです。

すべて場合は、エラーの詳細を通信しているため、ないRAISERRORを使用していますが、ストアドプロシージャは、クライアントが処理するエラーコードを返すことを考慮し、出力パラメータを使用しています。もちろん、外部クライアントが実際にSqlExceptionを取得しないため、このチェックを忘れてしまうリスクがあります。もう1つの選択肢は、あなたが渡したメッセージに必要なすべての細部をRAISERRORに、またはERROR_STATE()を小さな整数にエンコードすることです。これには依然としてストアドプロシージャを変更する必要があります。 TRY .. CATCHを使用することを意図している限り、その周りには方法がありません。

+1

この機能は、あなたが示唆しているように監視されている可能性がありますが、2012年のスルーは同じように機能します。これは私にとって意図的なデザインの決定に似ています。または、当初は彼らが去ることに決めた監督だったかもしれません;) –

+0

ありがとうございました。これは、私が不可能なことを求めていることをはっきりと示し、代替的なアプローチのための良い示唆を提供します。 – binki

+0

結果セットで解決しても、ストアドプロシージャの結果セットを他のT-SQLから使用することは不可能ではありませんか? – binki

関連する問題