Chèn vào chọn vào nhiều bảng có liên quan bằng INSERT_IDENTITY


10

Được rồi thiết lập cảnh. Tôi có ba bảng, ( Table1, Table2DataTable) và tôi muốn để chèn vào Table1Table2sử dụng DataTablenhư là nguồn. Vì vậy, đối với mỗi hàng trong DataTabletôi muốn có một hàng trong Table1Table2, và Table2cần phải chèn id(PK) từ Table1...

Nếu tôi làm điều này ...

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

Tôi sẽ nhận được IDbản ghi cuối cùng được chèn vào Table1.

Là một CURSORhoặc WHILEvòng lặp các cách duy nhất để làm điều này?

Câu trả lời:


10

Một giải pháp có thể phù hợp với bạn là sử dụng mệnh đề OUTPUT, giúp loại bỏ tất cả các hàng được chèn, do đó bạn có thể chèn lại chúng vào một bảng khác. Tuy nhiên, điều này đặt ra các hạn chế đối với các ràng buộc khóa ngoài trên Bảng2, nếu bộ nhớ phục vụ.

Dù sao, giải pháp sẽ trông giống như thế này:

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, trái ngược với các câu lệnh DML khác, có thể tham chiếu các bảng khác ngoài insertedvà chỉ deletedhữu ích cho bạn ở đây.

Thêm: http://sqlsunday.com/2013/08/04/cool-merge-features/


4

Nếu đây là việc bạn định làm thường xuyên (nghĩa là nó là một phần của logic ứng dụng chứ không phải là bài tập chuyển đổi dữ liệu một lần) thì bạn có thể sử dụng chế độ xem trên Bảng 1 và Bảng 2 với trình INSTEAD OF INSERTkích hoạt để quản lý phân tách dữ liệu (và sắp xếp các khóa / mối quan hệ) - sau đó bạn sẽ làm:

INSERT newView SELECT NEWID(), A, B, C, D, E, F FROM MyTable

và kích hoạt có thể đơn giản như:

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

giả sử quan điểm là một cái gì đó như:

CREATE VIEW newView AS 
SELECT table1.ID, A, B, C, D, E, F 
FROM table1 
    JOIN table2 ON table1.ID = table2.ID;

hoặc nếu có thể có các hàng trong mỗi bảng mà không khớp các hàng trong bảng khác:

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;

(tất nhiên các hàng được xuất ra khi bạn SELECTtừ chế độ xem là không quan trọng nếu bạn không có ý định SELECTtừ nó và nó chỉ tồn tại để cung cấp một khuôn mẫu để INSERTkích hoạt thực hiện phép thuật của nó)

Điều này giả định rằng bạn đang có ý định sử dụng loại UUID cho khóa chính của mình trong trường hợp này - nếu bạn đang sử dụng khóa số nguyên tự động tăng trên bảng1 thì sẽ còn nhiều việc phải làm. Một cái gì đó như sau có thể hoạt động:

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

và trên thực tế, cặp INSERTcâu lệnh có thể hoạt động trực tiếp như một lần như vậy (cho dù bạn đang sử dụng một INT IDENTITYhoặc UNIQUEIDENTIFIER DEFAULT NEWID()loại cho khóa):

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;

phủ nhận hoàn toàn nhu cầu về chế độ xem và kích hoạt, mặc dù nếu đây là thao tác bạn sẽ thực hiện thường xuyên trong mã của mình thì chế độ xem + kích hoạt vẫn đáng để xem xét để trừu tượng hóa nhu cầu cho nhiều câu lệnh mỗi lần.

CAVEAT: tất cả các SQL trên đã được nhập từ suy nghĩ và không được kiểm tra, nó sẽ cần làm việc trước khi có bất kỳ đảm bảo nào nó sẽ hoạt động như bạn cần.


3

Có vẻ như bạn muốn:

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>;

Hoặc có thể chỉ sử dụng một bảng, nếu bạn luôn có một hàng trong mỗi bảng ... bạn có lý do chính đáng để chia những bảng này thành nhiều bảng không?


1
Hệ thống đã hoạt động trước khi tôi làm việc với dự án và SE phụ trách muốn thử kế thừa bảng, sẽ ổn nếu bạn đang sử dụng Entity Framework và làm công cụ từ mã vì nó ẩn mọi thứ khỏi bạn nhưng khi bạn phải chuyển đổi đến ADO vì hiệu suất kém, đó là một cơn ác mộng!
m4rc

1

Từ việc đọc câu hỏi của bạn và nhận xét về các câu trả lời khác, có vẻ như bạn đang cố gắng khắc phục sự cố bằng DataTablecách chia nó thành hai bảng mới.

Tôi giả sử DataTablekhông có một trường duy nhất như là IDENTITY(1,1)? Nếu không, có lẽ bạn nên thêm một cái mà bạn có thể sử dụng để chèn dữ liệu vào Table1Table2.

Bằng một ví dụ; Tôi đã tạo một lược đồ mẫu, chèn dữ liệu thử nghiệm vào DataTable, sửa đổi DataTableđể có một IDENTITY(1,1)cột, sau đó sử dụng dữ liệu đó để chèn dữ liệu vào cả hai Table1Table2:

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

Điều này làm việc cho tôi, tôi biết nó trả lời rất muộn nhưng có thể giúp đỡ người khác. Tôi đã sử dụng IDENT_CURRENTnhận dạng hàng từ lần chèn trước, nhưng đối với tôi nó luôn là một hàng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.