私は今、私を怒らせているSQL関連の問題を抱えています:p. これが私のセットアップです:
私は2つのストアドプロシージャを持っています:
親ストアド プロシージャが呼び出されGenerateAnnualPenalty
ます。
GenerateAnnualPenalty
Properties
には SELECT CURSOR があり、 と呼ばれる一連のオブジェクトを反復し、 を適用する必要があるProperty
かどうかを判断します。Penalty
これは、 という名前のブール変数と、 または@ApplyPenalty
のいずれかに0
格納されます1
。また、 で使用されている SQL トランザクションはありませんGenerateAnnualPenalty
。
2 番目に、反復するそれぞれProperty
に対して、という名前の子ストアド プロシージャを呼び出します。への入力として渡されます。SQL トランザクション (コミット/ロールバック) を使用します。GenerateAnnualPenalty
GenerateAnnualPenaltyForProperty
@ApplyPenalty
GenerateAnnualPenaltyForProperty
GenerateAnnualPenaltyForProperty
という名前のテーブルにエントリを作成してDebugLog
、コード内の特定のポイントに到達したかどうかをマークします。
子のスケルトンは次のGenerateAnnualPenaltyForProperty
とおりです。
ALTER PROCEDURE [RTS].[GenerateAnnualPenaltyForProperty]
@PROPERTY_ID numeric(18,0),
@ApplyPenalty int
AS
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 1 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
DECLARE @TRANSACTION_NAME varchar(50)
SET @TRANSACTION_NAME = 'GenerateAnnualPenaltyForProperty'
BEGIN TRANSACTION @TRANSACTION_NAME
BEGIN TRY
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 2 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
IF @ApplyPenalty = 1
BEGIN
-- All main logic here !!!
END
COMMIT TRANSACTION @TRANSACTION_NAME
RETURN 0
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION @TRANSACTION_NAME
RETURN -1
END CATCH
問題 (イントロ):
GenerateAnnualPenalty
この特定の順序で4 を反復するとProperties
します (これは問題を悪用します)。
反復する最初のプロパティ:@PROPERTY_ID = 1
反復する 2 番目のプロパティ:@PROPERTY_ID = 2
反復する 3 番目のプロパティ:@PROPERTY_ID = 3
反復する 4 番目のプロパティ:@PROPERTY_ID = 4
プロパティ 1、3、および 4 についてApplyPenalty = 1
は 、プロパティ 2 については、ApplyPenalty = 0
問題 (主な核心):
プロパティ 1 に対して が呼び出されるとGenerateAnnualPenaltyForProperty
、すべて問題ありません。チェックポイント 1 とチェックポイント 2 の両方のエントリがDebugLog
テーブルに表示されます。
プロパティ 2 に対して が呼び出されるとGenerateAnnualPenaltyForProperty
、すべて正常に戻ります。チェックポイント 1 とチェックポイント 2 の両方のエントリがDebugLog
テーブルに表示されます。
プロパティ 3 に対して が呼び出されるとGenerateAnnualPenaltyForProperty
、間違ったシナリオが発生します。テーブルにはチェックポイント 1 エントリしかDebugLog
表示されませんが、'チェックポイント 2' エントリも表示されているはずです!
プロパティ 4 に対して が呼び出されるとGenerateAnnualPenaltyForProperty
、再び正しい結果が得られます。チェックポイント 1 とチェックポイント 2 の両方のエントリがDebugLog
テーブルに表示されます。
したがって、問題ApplyPenalty = 1
は、前の反復でApplyPenalty = 0
. このような場合、 のプロパティはApplyPenalty = 1
あたかもそうであるかのように扱われます。ApplyPenalty = 0
SQL トランザクション コードを無効にすると問題は解決しますが、その理由は?:
SQL トランザクションに関連するすべてのコードを無効にするとGenerateAnnualPenaltyForProperty
、すべて正常に動作します。上記の問題が修正されました。GenerateAnnualPenaltyForProperty
以下は、動作する SQL トランザクション コードが取り出された のスケルトンです。
ALTER PROCEDURE [RTS].[GenerateAnnualPenaltyForProperty]
@PROPERTY_ID numeric(18,0),
@ApplyPenalty int
AS
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 1 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
BEGIN TRY
insert into DebugLog (DebugMessage1, DebugMessage2, DebugMessage3, DebugMessage4)
values
('Checkpoint 2 for Property:', @PROPERTY_ID, 'Apply Penalty:', @ApplyPenalty)
IF @ApplyPenalty = 1
BEGIN
-- All main logic here !!!
END
RETURN 0
END TRY
BEGIN CATCH
RETURN -1
END CATCH
質問 (???):
なぜこの動作が発生するのですか? SQL トランザクションの commit/rollback into を使用するGenerateAnnualPenaltyForProperty
と、問題のあるケースでストアド プロシージャが機能しないのはなぜですか?
実際のコード:
子ストアド プロシージャの完全なコードを見たい場合は、https ://gist.github.com/anonymous/5214236 から入手できます。