1

検索するだけでいつでも答えを見つけることができるので、StackOverflowに質問を投稿する必要はありませんでした。今回だけ、本物のスタンパーを持っていると思います…。


あるSQLServerデータベースから別のデータベースにデータを移動するプロセスを自動化するコードを書いています。いくつかのテーブル間に外部キー関係を持つかなり標準的なSQLServerデータベースがいくつかあります。簡単なもの。私の要件の1つは、行をループしたりカーソルを使用したりせずに、テーブル全体を一挙にコピーする必要があることです。もう1つの要件は、SSISやその他の外部ヘルパーではなく、SQLでこれを実行する必要があることです。

例えば:

INSERT INTO TargetDatabase.dbo.MasterTable 
SELECT * FROM SourceDatabase.dbo.MasterTable

それは簡単です。次に、MasterTableのデータを移動したら、子テーブルのデータを移動します。

INSERT INTO TargetDatabase.dbo.ChildTable 
SELECT * FROM SourceDatabase.dbo.ChildTable

もちろん、実際にはもっと明示的なSQLを使用しています...すべてのフィールドなどに具体的に名前を付けるようにしていますが、これは単純化されたバージョンにすぎません。とにかく、これまでのところ、...を除いてすべてが順調に進んでいます。

問題は、マスターテーブルの主キーがIDフィールドとして定義されていることです。したがって、MasterTableに挿入すると、新しいテーブルの主キーがデータベースによって計算されます。そこで、これに対処するために、OUTPUT INTOステートメントを使用して、更新された値をTempテーブルに取得しようとしました。

INSERT INTO TargetDatabase.dbo.MasterTable 
OUPUT INSERTED.* INTO @MyTempTable
SELECT * FROM SourceDatabase.dbo.MasterTable

それで、ここですべてがバラバラになります。データベースが主キーを変更したので、一時テーブルのどのレコードがソーステーブルの元のレコードと一致するかを一体どうやって把握するのですか?

問題がわかりますか?新しいIDが何であるかはわかっていますが、元のレコードと確実に一致させる方法がわかりません。SQLサーバーでは、INSERTED値を出力できますが、FROMTABLE値をINSERTED値と一緒に出力することはできません。私はトリガーでそれを試しました、私はSPでそれを試しました、私はいつも同じ問題を抱えています。

一度に1つのレコードを更新するだけの場合、INSERTED値を挿入しようとした元のレコードと簡単に一致させて、新旧の主キー値を確認できますが、この要件をバッチで実行する必要があります。

何か案は?

PS:ターゲットまたはソーステーブルのテーブル構造を変更することは許可されていません。

4

2 に答える 2

3

MERGEを使用できます。

declare @Source table (SourceID int identity(1,2), SourceName varchar(50))
declare @Target table (TargetID int identity(2,2), TargetName varchar(50))

insert into @Source values ('Row 1'), ('Row 2')

merge @Target as T
using @Source as S
on 0=1
when not matched then
  insert (TargetName) values (SourceName)
output inserted.TargetID, S.SourceID;

結果:

TargetID    SourceID
----------- -----------
2           1
4           3

アダム・マハニックによるこのブログ投稿でカバーされています:Dr. OUTPUTまたは:心配をやめてMERGEを愛することをどのように学んだか

于 2012-07-28T08:03:37.803 に答える
0

コメントで私が言及したことを説明するために:

SET IDENTITY_INSERT TargetDatabase.dbo.MasterTable  ON

INSERT INTO TargetDatabase.dbo.MasterTable  (IdentityColumn, OtherColumn1, OtherColumn2, ...)
SELECT IdentityColumn, OtherColumn1, OtherColumn2, ... 
FROM SourceDatabase.dbo.MasterTable  

SET IDENTITY_INSERT TargetDatabase.dbo.MasterTable  OFF

さて、それはあなたにとってはうまくいかなかったので(ターゲットテーブルの既存の値)、両方のテーブルのID値に固定増分(オフセット)を追加するのはどうですか(現在の最大ID値を使用してください)。両方のテーブルでID列が「id」であると想定します。

DECLARE @incr int
BEGIN TRAN
SELECT @incr = max(id)
FROM TargetDatabase.dbo.MasterTable AS m WITH (TABLOCKX, HOLDLOCK)

SET IDENTITY_INSERT TargetDatabase.dbo.MasterTable ON

INSERT INTO TargetDatabase.dbo.MasterTable (id{, othercolumns...})
SELECT id+@incr{, othercolumns...}
FROM SourceDatabase.dbo.MasterTable

SET IDENTITY_INSERT TargetDatabase.dbo.MasterTable OFF

INSERT INTO TargetDatabase.dbo.ChildTable (id{, othercolumns...})
SELECT id+@incr{, othercolumns...} 
FROM SourceDatabase.dbo.ChildTable

COMMIT TRAN
于 2012-07-27T22:46:53.403 に答える