0

ヘッダー、サブヘッダー、および明細の詳細を含む注文を削除してから、代わりのサブヘッダー、明細の詳細が何であれ、同じ注文を書き出す必要があります。新しいバージョンに変更を書き戻そうとすると、pk 違反エラーが発生します。分析後、DELETE ステートメントが機能しているように見えても、それらを発行した後 (x 行が影響を受けるなど)、ターゲット テーブルは変更されていないことがわかります。したがって、これで pk vio の問題が説明されます。私は何が欠けていますか?

ステートメントの 1 つを次に示します。

       -- detail level (drop products)
       DELETE dprods FROM [SQLsever].[WIP].[order].DropProducts as dprods
        INNER JOIN #dropprods t on t.OrderId = dprods.OrderId
          AND t.OrderDropId = dprods.OrderDropId
          AND t.DropProdId = dprods.DropProdId;

ステートメントを発行した後、まだターゲット テーブルに 200 以上の行がすべてあり、#dropprods 一時テーブルに 200 以上の ID があります。なんで?

** 問題をより適切に定義するために編集** * ** * ** * ** * * DELETE ステートメントは問題ではありませんでした。この問題は、ネストされた/名前付きトランザクションのセットに関連付けられています。DELETE ステートメントは一方の下にあり、INSERT ステートメントは別の下にあります。これが私が持っているものです。明らかに間違っています。私がやろうとしているのは、適切な代替 INSERT があることを知る前に、DELETE をコミットしないことを保証することです。これが私がやったことです: *EDITED T-SQL WITH SAVE TRANSACTION FIX * ** この TSQL は動作するようになりました。

   -- CHANGED
   BEGIN TRANSACTION
   SAVE TRANSACTION process_orders
    BEGIN TRY
    -- detail level 
    DELETE lprods FROM [SQLServer].[WIP].[order].LiftProducts as lprods
     INNER JOIN #liftprods t on t.OrderId = lprods.OrderId
      AND t.OrderLiftId = lprods.OrderLiftId
      AND t.LiftProdId = lprods.LiftProdId;
           -- the rest of the deletes 
            --NOTE: No commit transaction here; saving it to the end
     END TRY
     BEGIN CATCH
        SELECT 
          ERROR_NUMBER() AS ErrorNumber, 
          ERROR_SEVERITY() AS ErrorSeverity,
          ERROR_MESSAGE() AS ErrorMessage;
         IF @@TRANCOUNT > 0
           ROLLBACK TRANSACTION process_orders;
       END CATCH

       BEGIN TRANSACTION 
        -- CHANGED
        SAVE TRANSACTION process_orders
       BEGIN TRY     
             -- CHANGED
                COMMIT TRANSACTION process_orders;     
       END TRY
       BEGIN CATCH
          SELECT 
            ERROR_NUMBER() AS ErrorNumber, 
            ERROR_SEVERITY() AS ErrorSeverity,
            ERROR_MESSAGE() AS ErrorMessage;
            IF @@TRANCOUNT > 0
              ROLLBACK TRANSACTION process_orders ;
       END CATCH 
4

1 に答える 1

1

まず、ROLLBACK TRANSACTION の後にトランザクション名を削除する必要があります。内部トランザクションはロールバックできません。ロールバックできるのは最も外側のトランザクションのみです。

次に、SQL サーバーは内部トランザクションのコミットを無視します (たとえば、ロックは最も外側のトランザクションがコミットされるまで待機し、その後解放されます)。したがって、トランザクション名のない COMMIT TRANSACTION は 1 つだけ必要です。

次のことを保証する必要がある場合、コードの実行に問題はありません。

  • 削除が成功した場合は挿入を開始し、失敗した場合は変更を破棄して
  • これらの挿入が成功した場合は変更を受け入れ、それ以外の場合はすべて破棄します

COMMITする前にさらに安心する必要がある場合(たとえば、別の開発者がSPに挿入コードを書いている、挿入コードが非常に大きいなど)、#liftprods一時テーブルを使用できます(明らかに削除/挿入するキーが含まれています) )、挿入する必要があると思われるアイテムとキーが一致するかどうかを確認します。そうでない場合は、トランザクションをロールバックする RAISERROR('Some message', 16, 1) を発行します。

于 2012-10-27T21:40:38.293 に答える