web-dev-qa-db-ja.com

SQL Serverで2つのテーブルに同時にデータを挿入するにはどうすればよいですか?

私のテーブル構造は次のように見えるとしましょう:

CREATE TABLE [dbo].[table1] (
    [id] [int] IDENTITY(1,1) NOT NULL,
    [data] [varchar](255) NOT NULL,
    CONSTRAINT [PK_table1] PRIMARY KEY CLUSTERED ([id] ASC)
)

CREATE TABLE [dbo].[table2] (
    [id] [int] IDENTITY(1,1) NOT NULL,
    [table1_id] [int] NOT NULL,
    [data] [varchar](255) NOT NULL,
    CONSTRAINT [PK_table2] PRIMARY KEY CLUSTERED ([id] ASC)
)

最初のテーブルの[id]フィールドは、2番目のテーブルの[table1_id]フィールドに対応しています。私がやりたいのは、単一のトランザクションで両方のテーブルにデータを挿入することです。これで、次のようにINSERT-SELECT-INSERTを実行してこれを行う方法が既にわかりました。

BEGIN TRANSACTION;
DECLARE @id [int];
INSERT INTO [table1] ([data]) VALUES ('row 1');
SELECT @id = SCOPE_IDENTITY();
INSERT INTO [table2] ([table1_id], [data]) VALUES (@id, 'more of row 1');
COMMIT TRANSACTION;

ほんの一握りの行を挿入するような小さなケースでは、これはすべて良いことです。しかし、私がしなければならないことは、数十万行、場合によっては数百万行を一度に挿入することです。データは別のテーブルから取得されるため、単一のテーブルにデータを挿入するだけであれば、簡単になります。これを行う必要があります。

INSERT INTO [table] ([data])
SELECT [data] FROM [external_table];

しかし、これをどのように行い、データを[table1][table2]に分割し、[table2]を適切な[table1_id]で更新しますか?それも可能ですか?

50
soapergem

これを試して:

insert into [table] ([data])
output inserted.id, inserted.data into table2
select [data] from [external_table]

更新:再:

デニス-これは私がやりたいことに非常に近いようですが、おそらく次のSQLステートメントを修正できますか?基本的に、[table1]の[data]と[table2]の[data]は、[external_table]とは異なる2つの異なる列を表します。上記で投稿したステートメントは、[data]列を同じにする場合にのみ機能します。

INSERT INTO [table1] ([data]) 
OUTPUT [inserted].[id], [external_table].[col2] 
INTO [table2] SELECT [col1] 
FROM [external_table] 

insertステートメントで外部列を出力することは不可能なので、次のようなことができると思います

merge into [table1] as t
using [external_table] as s
on 1=0 --modify this predicate as necessary
when not matched then insert (data)
values (s.[col1])
output inserted.id, s.[col2] into [table2]
;
30
Denis Valeev

私もこの問題に苦労しており、最良の方法は[〜#〜] cursor [〜#〜]を使用することであることがわかりました。

OUTPUTを使用してDenisソリューションを試しましたが、彼が述べたように、挿入ステートメントで外部列を出力することは不可能であり、選択によって複数の行を挿入するとMERGEは機能しません。

したがって、外側のテーブルの各行に対してCURSORを使用し、INSERTを実行してから、別のINSERTに@@ IDENTITYを使用しました。

DECLARE @OuterID int

DECLARE MY_CURSOR CURSOR 
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR 
SELECT  ID FROM   [external_Table]

OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @OuterID

WHILE @@FETCH_STATUS = 0
BEGIN 
INSERT INTO [Table]   (data)
    SELECT data
    FROM     [external_Table] where ID = @OuterID 

    INSERT INTO [second_table] (FK,OuterID)
    VALUES(@OuterID,@@identity)

    FETCH NEXT FROM MY_CURSOR INTO @OuterID
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
4
IFink

「INSERT ALL」ステートメントをサポートするSQL Serverに注目してください。 Oracleにはすでにあります。次のようになります( SQL Cookbook ):

insert all
  when loc in ('NEW YORK', 'BOSTON') THEN
   into dept_east(deptno, dname, loc) values(deptno, dname, loc)
  when loc in ('CHICAGO') THEN
   into dept_mid(deptno, dname, loc) values(deptno, dname, loc)
  else
   into dept_west(deptno, dname, loc) values(deptno, dname, loc)
select deptno, dname, loc
  from dept
1
Brian
BEGIN TRANSACTION;

DECLARE @tblMapping table(sourceid int, destid int)

INSERT INTO [table1] ([data]) 
OUTPUT source.id, new.id
Select [data] from [external_table] source;

INSERT INTO [table2] ([table1_id], [data])
Select map.destid, source.[more data] 
from [external_table] source
    inner join @tblMapping map on source.id=map.sourceid;

COMMIT TRANSACTION;
0
Bill

別のオプションは、2つの挿入を個別に実行し、FK列をNULLのままにしてから、更新を実行して正しく挿入することです。

あるレコードから別のレコードに一致する(おそらく)2つのテーブル内に自然なものが何も保存されていない場合は、一時的なGUID=列を作成し、これをデータに入力して両方のフィールドに挿入します。適切なFKで更新し、GUIDを無効にします。

例えば。:

CREATE TABLE [dbo].[table1] ( 
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [data] [varchar](255) NOT NULL, 
    CONSTRAINT [PK_table1] PRIMARY KEY CLUSTERED ([id] ASC),
    JoinGuid UniqueIdentifier NULL
) 

CREATE TABLE [dbo].[table2] ( 
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [table1_id] [int] NULL, 
    [data] [varchar](255) NOT NULL, 
    CONSTRAINT [PK_table2] PRIMARY KEY CLUSTERED ([id] ASC),
    JoinGuid UniqueIdentifier NULL
) 


INSERT INTO Table1....

INSERT INTO Table2....

UPDATE b
SET table1_id = a.id
FROM Table1 a
JOIN Table2 b on a.JoinGuid = b.JoinGuid
WHERE b.table1_id IS NULL

UPDATE Table1 SET JoinGuid = NULL
UPDATE Table2 SET JoinGuid = NULL
0
cjk
Create table #temp1
(
 id int identity(1,1),
 name varchar(50),
 profession varchar(50)
)

Create table #temp2
(
 id int identity(1,1),
 name varchar(50),
 profession varchar(50)
)

-----メインクエリ------

insert into #temp1(name,profession)

output inserted.name,inserted.profession into #temp2

select 'Shekhar','IT'
0
Shekhar Kumar