SQL Server:2つのテーブルに同時に挿入することは可能ですか?


143

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

私はからデータをコピーするDATA_TABLEことは、1つの与えられたオブジェクトIDにとにレコードを挿入し、対応するリンクされている場所Data_TableLink_Table異なる特定のオブジェクト識別のために。

これ行うには、テーブル変数を選択し、反復ごとに2つの挿入を実行してループします。

これはそれを行うための最良の方法ですか?

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

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


2つの挿入で完全に機能する場合、1つの挿入でそれを実行しようとしても興味がありません。2つの挿入が両方とも完了していることを確認しますか?次に、このコミット/ロールバックの指示を確認する必要があります。
フィリップグロニエ2008年

2
私は2つの挿入に満足しています。リンクテーブルに挿入する必要があるIDが、最初の挿入で生成されたIDであるというだけです。
tpower 2008年

回答:


219

1つのステートメントで:いいえ。

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

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

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


2
これは私が長い間探し求めているものです。ありがとう:)
nandu.com

33
@ジョエル、素晴らしい質問。おそらく誰かが別の現実を望み、あなたは悪い知らせの持ち主でした。;)
カークウォル2009

2
今日は私の日を救った:) thanx
Shekhar_Pro

12
これは問題を解決しません。彼はObject_Tableから読み取ったデータを挿入したいと考えています。すなわちinsert into ... select ...声明。上記のコードはどのようにObject_Tableデータを読み取るかループしますか。それでも、質問者がしたくないテーブル変数を使用する必要があります。
hofnarwillie 2013

8
確かにこれで問題は解決します。多分私はこれのためにすべてのコードを書いたわけではありませんが、それからOPは彼がコピーしたいすべての列を共有しませんでした。この回答で示されている機能により、OPは彼が求めていることを実行できます...クエリを実行してレコードを作成し、新しいレコードのIDを取得し、そのIDを2番目のレコードにアトミックな方法で使用します。OPはすでに挿入/選択の方法を知っています。これは彼が欠けていた作品です。
Joel Coehoorn、2015年

35

あなたはまだ2人の必要なINSERT発言をしていますが、取得したいように聞こえるIDENTITY最初の挿入から、および第二に、それを使用し、その場合には、あなたがに見たいと思うかもしれませんOUTPUTOUTPUT INTOhttp://msdn.microsoft.com/en- us / library / ms177564.aspx


1
ありがとう!正確に私が探していたOUTPUTキーワードについて知りませんでした。+1
レックスモーガン

1つのSQLで「OUTPUT INTO」を2回使用することは可能ですか
V.Wu

@ V.Wu私はそうは思わない、私は見るためにテストを設定する必要があります。
Cade Roux

18

以下は、テーブル変数を使用して、状況を設定します。

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

私を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一時テーブルを作成して、通常の挿入で終了できます。したがって、ループを回避できますが、一時テーブルは回避できません。



6

リンクテーブルは、オブジェクトテーブルとデータテーブルの間の多対多の関係をキャプチャしているようです。

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

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


なぜ誰もあなたに賛成しなかったのですか?ストアドプロシージャは明白で最良の方法です。あなたの答えをジョエル・コーホーンの答えと組み合わせると、最高の答えが得られます!
Rhyous、2014

4

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


2
「多かれ少なかれ」アトミックではなく、トランザクションにラップされている場合、アクションはアトミックです。あなたがそう指定しない限り、必ずしも保証されないのは分離のレベルです。
Dave Markle、

4

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


4

使って強調したい

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

2

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

テーブル変数をループする必要があることはわかりません。一方のテーブルに大量挿入を使用してから、もう一方のテーブルに大量挿入を使用することはできませんか?

ちなみに、Object_Tableからデータをコピーしているのではないでしょうか。そうでなければ、質問は意味がありません。


2

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


-1
-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters 
-- command (Ctrl-Shift-M) to fill in the parameter 
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE InsetIntoTwoTable

(
@name nvarchar(50),
@Email nvarchar(50)
)

AS
BEGIN

    SET NOCOUNT ON;


    insert into dbo.info(name) values (@name)
    insert into dbo.login(Email) values (@Email)
END
GO

説明を追加していただけますか?
2015年

-2

//最初のテーブルと同じものを挿入したい場合

$qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";

$result = @mysql_query($qry);

$qry2 = "INSERT INTO table2 (one,two, three) VVALUES('$one','$two','$three')";

$result = @mysql_query($qry2);

//または表1の特定の部分を挿入する場合

 $qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";


  $result = @mysql_query($qry);

 $qry2 = "INSERT INTO table2 (two) VALUES('$two')";

 $result = @mysql_query($qry2);

//私はそれが正しくないように見えますが、それは機能し、クエリを追加し続けるだけで変更できます

    "$qry"-number and number in @mysql_query($qry"")

これが機能しているテーブルが17あります。


インサートの途中で問題が発生した場合 挿入は不完全になります。正しい?そうする場合..それを処理するロールバック機能はありますか?そうでない場合は、データの整合性に問題があります。
ディープセル

7
-1。この答えは、PHPでMySQLメソッドを使用しているようです。質問のタグはsqlおよびsql-serverで、MySQLやPHPについては言及されていません。
mskfisher 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.