web-dev-qa-db-ja.com

SQL Server:2つのテーブルに同時に挿入できますか?

私のデータベースには、Object_TableData_TableLink_Tableという3つのテーブルが含まれています。リンクテーブルには、オブジェクトレコードのIDとデータレコードのIDの2つの列が含まれています。

特定のオブジェクトIDにリンクされているDATA_TABLEからデータをコピーし、別の特定のオブジェクトIDの対応するレコードをData_TableおよびLink_Tableに挿入します。

I canテーブル変数を選択し、反復ごとに2つの挿入を実行することでこれを行います。

これが最善の方法ですか?

編集:ループを回避したい理由は2つあります。1つ目は、私が怠け者であり、ループ/一時テーブルに多くのコードが必要であるということです。パフォーマンスに関する懸念です。

1回の挿入ですべてのデータをコピーできますが、各レコードに新しいIDがある新しいデータレコードにリンクテーブルをリンクするにはどうすればよいですか?

127
tpower

以下は、テーブル変数を使用して、私が持っていた状況を設定します。

DECLARE @Object_Table TABLE
(
    Id INT NOT NULL PRIMARY KEY
)

DECLARE @Link_Table TABLE
(
    ObjectId INT NOT NULL,
    DataId INT NOT NULL
)

DECLARE @Data_Table TABLE
(
    Id INT NOT NULL Identity(1,1),
    Data VARCHAR(50) NOT NULL
)

-- create two objects '1' and '2'
INSERT INTO @Object_Table (Id) VALUES (1)
INSERT INTO @Object_Table (Id) VALUES (2)

-- create some data
INSERT INTO @Data_Table (Data) VALUES ('Data One')
INSERT INTO @Data_Table (Data) VALUES ('Data Two')

-- link all data to first object
INSERT INTO @Link_Table (ObjectId, DataId)
SELECT Objects.Id, Data.Id
FROM @Object_Table AS Objects, @Data_Table AS Data
WHERE Objects.Id = 1

別の answer のおかげで、私はOUTPUT句を示し、解決策を示すことができます。

-- now I want to copy the data from from object 1 to object 2 without looping
INSERT INTO @Data_Table (Data)
OUTPUT 2, INSERTED.Id INTO @Link_Table (ObjectId, DataId)
SELECT Data.Data
FROM @Data_Table AS Data INNER JOIN @Link_Table AS Link ON Data.Id = Link.DataId
                INNER JOIN @Object_Table AS Objects ON Link.ObjectId = Objects.Id 
WHERE Objects.Id = 1

ただし、次のエラーのために実際の生活ではそれほど単純ではないことがわかります

oUTPUT INTO句は(主キー、外部キー)関係のどちら側にもできません

一時テーブルをOUTPUT INTOして、通常の挿入で終了できます。したがって、ループを回避できますが、一時テーブルは回避できません。

18
tpower

1つ:いいえ.

1つトランザクション:はい

BEGIN TRANSACTION
   DECLARE @DataID int;
   INSERT INTO DataTable (Column1 ...) VALUES (....);
   SELECT @DataID = scope_identity();
   INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT

幸いなことに、上記のコードもatomicであることが保証されており、1つのステートメントであるかのように、1つの関数呼び出しで1つのsql文字列を使用してクライアントアプリケーションからサーバーに送信できます。また、1つの挿入の効果を得るために、1つのテーブルにトリガーを適用することもできます。ただし、最終的にはまだ2つのステートメントであるため、おそらくevery insertのトリガーを実行したくないでしょう。

203
Joel Coehoorn

Linkテーブルは、ObjectテーブルとDataテーブル間のmany:many関係をキャプチャしているようです。

私の提案は、ストアドプロシージャを使用してトランザクションを管理することです。オブジェクトまたはデータテーブルに挿入する場合は、挿入を実行し、新しいIDを取得して、リンクテーブルに挿入します。

これにより、すべてのロジックを1つの呼び出しやすいsprocにカプセル化したままにできます。

6
Bob Probst

アクションを多かれ少なかれアトミックにしたい場合は、トランザクションでラップするようにします。そうすれば、必要に応じて両方が発生したか、両方が発生しなかったかを確認できます。

4
Craig

使用に重点を置きたい

SET XACT_ABORT ON;

複数のsqlステートメントを持つMSSQLトランザクションの場合。

参照: https://msdn.Microsoft.com/en-us/library/ms188792.aspx 非常に良い例です。

したがって、最終的なコードは次のようになります。

SET XACT_ABORT ON;

BEGIN TRANSACTION
   DECLARE @DataID int;
   INSERT INTO DataTable (Column1 ...) VALUES (....);
   SELECT @DataID = scope_identity();
   INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT
4
Sergei Zinovyev

挿入ステートメントに必要な列名を選択するビューを作成し、INSTEAD OF INSERTトリガーを追加して、このビューに挿入します。

4
devio

挿入は、一度に1つのテーブルに対してのみ操作できます。複数の挿入には複数のステートメントが必要です。

テーブル変数をループ処理する必要があることはわかりません。1つのテーブルに一括挿入を使用してから、別のテーブルに一括挿入を使用することはできませんか?

ところで-Object_Tableからデータをコピーすることを意味すると思います。それ以外の場合、質問は意味がありません。

2
Carlton Jenke

Oracleでマルチテーブル挿入を実行する前に、挿入を実行するINSTEAD OFトリガーが定義されているビューへの挿入を伴うトリックを使用できます。これはSQL Serverで実行できますか?

2
David Aldridge