シーンを設定してみましょう。 3つのテーブル(Table1
、Table2
、DataTable
)があり、DataTable
をソースとして使用して、Table1
とTable2
に挿入したいと思います。したがって、DataTable
のすべての行について、Table1
とTable2
の行が必要です。Table2
には、Table1
からid
(PK)を挿入する必要があります...
私がこれをするなら...
INSERT INTO Table1 SELECT A, B, C FROM MyTable
INSERT INTO Table2 SELECT IDENTITY_INSERT(), D, E, F FROM MyTable
最後に挿入されたレコードのID
をTable1
に取得します。
CURSOR
またはWHILE
ループがこれを行う唯一の方法ですか?
mightが機能する解決策は、挿入されたすべての行を出力するOUTPUT句を使用しているため、別のテーブルに再挿入できます。 。ただし、メモリが機能する場合、これによりTable2の外部キー制約に制限が課されます。
とにかく、ソリューションは次のようになります。
MERGE INTO Table1 AS t1
USING MyTable ON 1=0 -- always generates "not matched by target"
WHEN NOT MATCHED BY TARGET THEN
-- INSERT into Table1:
INSERT (A, B, C) VALUES (t1.A, t1.B, t1.C)
--- .. and INSERT into Table2:
OUTPUT inserted.ID, MyTable.D, MyTable.E, MyTable.F
INTO Table2 (ID, D, E, F);
MERGEは、他のDMLステートメントとは対照的に、inserted
とdeleted
以外のテーブルを参照できます。これは、ここで役立ちます。
これが定期的に行う予定の場合(つまり、アプリケーションロジックの一部であり、1回限りのデータ変換演習ではない)、_INSTEAD OF INSERT
_トリガーを使用してTable1およびTable2へのビューを使用して分割を管理できます。データ(およびキー/関係の配置)-次に、次のようにします。
_INSERT newView SELECT NEWID(), A, B, C, D, E, F FROM MyTable
_
トリガーは次のように簡単にすることができます。
_CREATE trg_newview_insert TRIGGER newView INSTEAD OF UPDATE AS
INSERT table1 SELECT ID, A, B, C FROM inserted
INSERT table2 SELECT ID, D, E, F FROM inserted
GO
_
ビューが次のようなものであると仮定します:
_CREATE VIEW newView AS
SELECT table1.ID, A, B, C, D, E, F
FROM table1
JOIN table2 ON table1.ID = table2.ID;
_
または、他の行と一致しない行が各テーブルにある可能性がある場合:
_CREATE VIEW newView AS
SELECT ISNULL(table1.ID, table2.ID), A, B, C, D, E, F
FROM table1
FULL OUTER JOIN table2 ON table1.ID = table2.ID;
_
(もちろん、ビューからSELECT
したときに出力される行は、そこからSELECT
するつもりがなく、テンプレートをINSERT
に提供するためだけに存在する場合、重要ではありません。トリガーが魔法をかけるために)
これは、この場合に主キーにUUIDタイプを使用することを想定しています。table1で自動的に増分する整数キーを使用している場合は、もう少し作業が必要です。次のようなものが機能する可能性があります。
_CREATE trg_newview_insert TRIGGER newView INSTEAD OF UPDATE AS
INSERT table1 (A, B, C)
SELECT A, B, C
FROM inserted;
INSERT table2 (ID, D, E, F)
SELECT ID, D, E, F
FROM table1 AS t
JOIN inserted AS i ON t.A = i.A AND t.B = i.B AND t.C = i.C;
GO
_
実際には、ペアのINSERT
ステートメントは、キーに_INT IDENTITY
_またはUNIQUEIDENTIFIER DEFAULT NEWID()
タイプを使用しているかどうかにかかわらず、1回限りのように直接機能する可能性があります):
_INSERT table1 (A, B, C)
SELECT A, B, C
FROM MyTable;
INSERT table2 (ID, D, E, F)
SELECT ID, D, E, F
FROM table1 AS t
JOIN MyTable AS i ON t.A = i.A AND t.B = i.B AND t.C = i.C;
_
ビューとトリガーの必要性を完全に否定しますが、これがコード内で頻繁に実行される操作である場合、ビューとトリガーは、毎回複数のステートメントの必要性を抽象化することを検討する価値があります。
警告:上記のSQLはすべて、思考から型付けされており、テストされていません。必要に応じて機能することが保証される前に、機能する必要があります。
あなたが望むようです:
INSERT dbo.Table1(A,B,C) SELECT A,B,C
FROM dbo.DataTable WHERE <identify one row>;
INSERT dbo.Table2(ID,D,E,F) SELECT SCOPE_IDENTITY(),D,E,F
FROM dbo.DataTable WHERE <identify that same row>;
または、各テーブルに常に行がある場合は、1つのテーブルを使用するだけかもしれません...これらを複数のテーブルに分割する十分な理由はありますか?
質問と他の回答のコメントを読んでいると、DataTable
の問題を2つの新しいテーブルに分割することで問題を解決しようとしているようです。
DataTable
にはIDENTITY(1,1)
のような単一の一意のフィールドがまだないのでしょうか?そうでない場合は、おそらくTable1
およびTable2
にデータを挿入するために使用できるものを追加する必要があります。
例として、サンプルスキーマを作成し、テストデータをDataTable
に挿入し、DataTable
を変更してIDENTITY(1,1)
列を作成し、それを使用してTable1
とTable2
の両方にデータを挿入しました。
USE tempdb;
GO
CREATE TABLE dbo.DataTable
(
A INT
, B INT
, C INT
, D INT
, E INT
, F INT
);
INSERT INTO dbo.DataTable (A, B, C, D, E, F)
VALUES (1, 2, 3, 11, 12, 13)
, (4, 5, 6, 14, 15, 16)
, (7, 8, 9, 17, 18, 19);
CREATE TABLE dbo.Table1
(
Table1PK INT NOT NULL CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED IDENTITY(1,1)
, A INT
, B INT
, C INT
);
CREATE TABLE dbo.Table2
(
Table2PK INT NOT NULL CONSTRAINT PK_Table2 PRIMARY KEY CLUSTERED IDENTITY(1,1)
, Table1PK INT NOT NULL CONSTRAINT FK_Table2_Table1_PK FOREIGN KEY REFERENCES dbo.Table1(Table1PK)
, D INT
, E INT
, F INT
);
ALTER TABLE dbo.DataTable ADD TempCol INT NOT NULL IDENTITY(1,1);
SET IDENTITY_INSERT dbo.Table1 ON;
INSERT INTO Table1 (Table1PK, A, B, C)
SELECT TempCol, A, B, C
FROM DataTable;
SET IDENTITY_INSERT dbo.Table1 OFF;
INSERT INTO Table2
SELECT Table1PK, D, E, F
FROM dbo.DataTable DT
INNER JOIN dbo.Table1 T ON DT.TempCol = T.Table1PK;
SELECT *
FROM dbo.Table1;
SELECT *
FROM dbo.Table2;