私のテーブル構造は次のように見えるとしましょう:
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]
で更新しますか?それも可能ですか?
これを試して:
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]
;
私もこの問題に苦労しており、最良の方法は[〜#〜] 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
「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
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;
別のオプションは、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
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'