私は今、私を怒らせているSQL関連の問題を抱えています:p. これが私のセットアップです:
私は2つのストアドプロシージャを持っています:
親ストアド プロシージャが呼び出されGenerateAnnualPenaltyます。
GenerateAnnualPenaltyPropertiesには SELECT CURSOR があり、 と呼ばれる一連のオブジェクトを反復し、 を適用する必要があるPropertyかどうかを判断します。Penaltyこれは、 という名前のブール変数と、 または@ApplyPenaltyのいずれかに0格納されます1。また、 で使用されている SQL トランザクションはありませんGenerateAnnualPenalty。
2 番目に、反復するそれぞれPropertyに対して、という名前の子ストアド プロシージャを呼び出します。への入力として渡されます。SQL トランザクション (コミット/ロールバック) を使用します。GenerateAnnualPenaltyGenerateAnnualPenaltyForProperty@ApplyPenaltyGenerateAnnualPenaltyForPropertyGenerateAnnualPenaltyForProperty
という名前のテーブルにエントリを作成して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 から入手できます。