INSERT_IDENTITYを使用して、selectに複数の関連テーブルに挿入します


10

シーンを設定してみましょう。私は、3つのテーブルを持っている(Table1Table2およびDataTable)、私はに挿入するTable1と、Table2使用してDataTableソースとして。だから、内のすべての行のためにDataTable私の行をしたいTable1Table2、そしてTable2挿入されている必要がありidから(PK)をTable1...

私がこれをするなら...

INSERT INTO Table1 SELECT A, B, C FROM MyTable
INSERT INTO Table2 SELECT IDENTITY_INSERT(), D, E, F FROM MyTable

ID最後に挿入されたレコードのをに取得しTable1ます。

これを行う唯一の方法はCURSORor WHILEループですか?

回答:


10

うまくいくかもしれない解決策は、挿入されたすべての行を吐き出す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ステートメントとは対照的に、insertedand だけでなく他のテーブルを参照deletedできます。これは、ここで役立ちます。

詳細:http : //sqlsunday.com/2013/08/04/cool-merge-features/


4

これが定期的に行う予定の場合(つまり、アプリケーションロジックの一部であり、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はすべて、思考から型付けされており、テストされていません。必要に応じて機能することが保証される前に、機能する必要があります。


3

あなたが望むようです:

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つのテーブルを使用するだけかもしれません...これらを複数のテーブルに分割する十分な理由はありますか?


1
私がプロジェクトに取り組む前にシステムが整っていて、担当のSEがテーブルの継承を試してみたかったのですが、Entity Frameworkを使用してコードから何かを実行している場合は問題ありません。パフォーマンスが悪いためにADOを使用するのは悪夢です。
m4rc 2014

1

質問と他の回答のコメントを読んでいると、問題をDataTable2つの新しいテーブルに分割して問題を解決しようとしているようです。

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;

-1
INSERT INTO VouchersOtherDetail (
                                 [VouNo],
                                 [Location],
                                 [VouType],
                                 [VouDate],
                                 [InputDate],
                                 [CrossRefGoodsVouNo],
                                 [Reversed],
                                 [ReversalReference],
                                 [UserID]
                                 ) 
SELECT   
                                [VouNo],
                                [Location],
                                [VouType],
                                [VouDate],
                                [InputDate],
                                [CrossRefGoodsVouNo],
                                [Reversed],
                                [ReversalReference],
                                [UserID]
FROM @InsertTableForVoucherDetail           

INSERT INTO VouchersDrCrDetail (
                                [VouID],
                                [AccountCode],
                                [CrossReferAccountCode],
                                [Description],
                                [VouDrAmount],
                                [VouCrAmount],
                                [RunningBalance]
                               )
SELECT  -- IDENT_CURRENT to get the identity of row from previous insert
                                 IDENT_CURRENT('VouchersOtherDetail'), 
                                 [AccountCode],
                                 [CrossReferAccountCode],
                                 [Description],
                                 [VouDrAmount],
                                 [VouCrAmount],
                                 [RunningBalance]
FROM @InsertTableForDrAndCR

これは私にとってはうまくいきました、私はその非常に遅い返信を知っていますが、他の人を助けるかもしれません。IDENT_CURRENT以前の挿入から行のIDを取得するのに使用しましたが、私にとっては常に1行です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.