INSERT_IDENTITY kullanarak birden çok ilişkili tabloya seçime ekleyin


10

Tamam, sahneyi kurduk. Üç tablo var, ( Table1, Table2ve DataTable) ve kaynak olarak eklemek Table1ve Table2kullanmak istiyorum DataTable. Yani her satır için DataTablebir satır istiyorum Table1ve Table2, ve Table2eklenen id(PK) Table1...

Bunu yapsaydım ...

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

Ben alırdım IDiçine son eklenen kaydın Table1.

Bir CURSORveya WHILEdöngü bunu yapmanın tek yolu mu?

Yanıtlar:


10

O bir çözüm kudreti yeniden eklemek için bu özellikler, farklı bir tabloya sizin için çalışması, tüm eklenen satırlar tükürür ÇIKIŞ maddesini kullanmaktadır. Ancak, bellek çalışıyorsa, bu durum Tablo2'de yabancı anahtar kısıtlamalarına sınırlamalar getirir.

Her neyse, çözüm şöyle görünecektir:

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, diğer DML ifadelerinin aksine, sadece dışında başka tablolara başvurabilir insertedve deletedbu da sizin için yararlıdır.

Daha fazlası: http://sqlsunday.com/2013/08/04/cool-merge-features/


4

Bu düzenli olarak yapmayı planladığınız bir şeyse (yani bir kereye mahsus veri dönüştürme alıştırması değil, uygulama mantığının bir parçasıdır) INSTEAD OF INSERT, verilerin bölünmesini yönetmek (ve düzenlemek) için bir tetikleyici ile Tablo1 ve Tablo2'ye bir görünüm kullanabilirsiniz. anahtarlar / ilişkiler) - o zaman yapmanız gerekenler:

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

ve tetik şu kadar basit olabilir:

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

manzaranın şöyle olduğunu varsayarsak:

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

veya her tabloda, diğerinde eşleşen satırlar olmadan satırlar varsa:

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;

(elbette SELECT, görünümden siz istemiyorsanız hangi satırların çıktısı önemsizdir SELECTve yalnızca INSERTtetikleyicinin sihrini yapması için içine bir şablon sağlamak için var olur )

Bu, bu durumda birincil anahtarınız için bir UUID türü kullanmayı planladığınızı varsayar - table1'de otomatik olarak artan bir tam sayı anahtarı kullanıyorsanız, yapmanız gereken daha fazla iş vardır. Aşağıdaki gibi bir şey işe yarayabilir:

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

ve aslında bir çift INSERTifade doğrudan bir kereye mahsus gibi çalışabilir ( anahtar için bir INT IDENTITYveya UNIQUEIDENTIFIER DEFAULT NEWID()tür kullanıyor olsanız da ):

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;

görünüm ve tetikleyici ihtiyacını tamamen ortadan kaldırır, ancak bu bir kod ise sık sık gerçekleştireceğiniz bir işlemse, görünüm + tetikleyici yine de her seferinde birden fazla ifade ihtiyacını soyutlamaya değer olacaktır.

CAVEAT: yukarıdaki tüm SQL düşünce yazılmıştır ve test edilmemiştir, ihtiyacınız olduğu gibi çalışacağına dair herhangi bir garanti olmadan önce çalışmaya ihtiyaç duyacaktır.


3

İstediğiniz gibi görünüyor:

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

Ya da belki sadece bir tablo kullanın, her tabloda bir satır olacaksanız ... bunları birden fazla tabloya bölmek için iyi bir nedeniniz var mı?


1
Proje üzerinde çalışmadan önce sistem yerinde idi ve sorumlu SE tablo mirasını denemek istedi, ki Entity Framework kullanıyorsanız ve sizden her şeyi gizlediğinden ancak geçiş yapmanız gerektiğinde koddan bir şeyler yapıyorsanız sorun yok düşük performans nedeniyle ADO'ya bir kabus!
m4rc

1

Sorunuzu ve diğer yanıtlardaki yorumları okuduğunuzda, bir sorunu DataTableiki yeni tabloya bölerek çözmeye çalıştığınız anlaşılıyor .

DataTableZaten bir gibi tek bir benzersiz alan yok varsayalım IDENTITY(1,1)? Değilse, Table1ve içine veri eklemek için kullanabileceğiniz bir tane eklemeniz gerekebilir Table2.

Örnek olarak; Bir örnek şema oluşturdum, içine test verisi ekledim DataTable, DataTablebir IDENTITY(1,1)sütuna sahip olacak şekilde değiştirdim , sonra her ikisine de veri eklemek için kullandım Table1ve 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

Bu şey benim için çalıştı, çok geç cevabını biliyorum ama başkalarına yardımcı olabilir. Ben IDENT_CURRENTönceki ek satırdan kimliğini almak kullanılan , ama benim için her zaman bir satır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.