あるテーブルから別のテーブルへの行の移動


9

アーカイブプロセスの一環として、あるデータベースから別のデータベースにレコードを移動しています。行を宛先テーブルにコピーしてから、同じ行をソーステーブルから削除します。

私の質問は、行を削除する前に最初の挿入が成功したかどうかを確認する最も効率的な方法は何ですか?

私の考えはこれですが、もっと良い方法があると思います:

@num_records=select count(ID) from Source_Table where (criteria for eligible rows)

insert * into Destination_Table where (criteria for eligible rows)

if ((select count(ID) from Destination_Table where (criteria) )=@numrecords)

delete * from Source_Table where (criteria)

RAISERROR関数と組み合わせるのが良いですか?ありがとうございました!

回答:


13

明示的なトランザクションとともにTRY / CATCH構文をお勧めします。このソリューションの私の仮定は、挿入の失敗の理由がトラップ可能なSQLエラー(キー違反、データ型の不一致/変換エラーなど)であるということです。構造は次のようになります。

BEGIN TRAN

BEGIN TRY
  INSERT INTO foo(col_a,col_b,col_c,recdate)
  SELECT col_a,col_b,col_c,recdate
  FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  DELETE FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  COMMIT TRAN
END TRY
BEGIN CATCH
  ROLLBACK TRAN
END CATCH

この構造が機能する方法では、INSERTまたはDELETEでエラーが発生した場合、アクション全体がロールバックされます。これにより、アクション全体が正常に完了する必要があります。必要だと感じた場合は、それを2012年のTHROWまたは2008年以前のRAISERRORと組み合わせて追加のロジックを追加し、そのロジックが満たされていない場合は強制的にロールバックできます。

別のオプションは、SET XACT_ABORT ONを確認することですが、TRY / CATCH構文を使用すると、よりきめ細かくできると思います。


19

アーカイブテーブルがそうでない場合

  • その上で定義されたトリガーを有効にします。
  • FOREIGN KEY制約のいずれかの側に参加します。
  • CHECK制約または有効なルールがあります。

1つの州でそれを行うこともできます。

DELETE FROM source_table
OUTPUT deleted.Foo,
       deleted.Bar,
       SYSUTCDATETIME()
INTO archive_table(Foo, Bar, archived)
WHERE  Foo = 1; 

これは、1つのユニットとして成功または失敗し、行がINSERTアーカイブとの間に追加される可能性のある競合状態を回避しDELETEます(WHEREとにかく、これにより、非常に可能性が低くなります)。


上記のどれでもない。私はその道を進むことができると思います、私はコードミニマリズムが好きです。何らかの理由で挿入が失敗した場合でも、レコードを失いたくないだけです。(つまり:テーブルのロック、タイムアウトなど)ありがとうございます。
Dina

@ディーナ- OUTPUT条項で可能であることを示していましたか?それはすべて1つのステートメントであるためではありません。行を2回読み取る必要があるという問題(および、挿入の読み取りと削除の読み取りの間に追加された行が失われる可能性も)を回避します
Martin Smith

はい、そういう意味です。ありがとうございます。
2013年

FWIW-この方法では、元のテーブルのサイズに近いログファイルの増加が発生します。あなたがそれに耐えられることを確認してください。できない場合は、DELETE TOP(N)と@@ rowcount変数をチェックするWhileループを使用してバッチに分割します。
Wjdavis5 2016年

1

アーカイブを行うことについて私が考えた方法(これも完璧ではないことは間違いありません)は、「Archived」のような新しいアーカイブテーブルにビット列を追加することです。また、すべてのレコードを転送したら、アーカイブされたテーブルからこの「アーカイブ済み」フィールドの値「1」、つまりTrueを探しながら、削除操作を実行できます。

そして、Try / Catchの使用に関してマイクに同意します。


1

これを試して:

INSERT dbo.newtable(
      name,
      department,
      Salary
) SELECT 
            name,
            FirstName,
            Lastname
      FROM    (
           DELETE dbo.oldtable
           OUTPUT
                   DELETED.name,
                   DELETED.department,
                   DELETED.Salary
           WHERE ID  IN ( 1001, 1003, 1005 )
      ) AS RowsToMove;

SELECT * FROM dbo.newtable;
SELECT * FROM dbo.oldtable;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.