Zde popsané řešení bude správně fungovat ve víceuživatelském prostředí.
Použil bych MERGE
s OUTPUT doložka.
MERGE může INSERT , UPDATE a DELETE řádky. V tomto případě potřebujeme pouze INSERT .
1=0 je vždy nepravda, takže NOT MATCHED BY TARGET část se vždy provede. Obecně mohou existovat další větve, viz dokumenty.WHEN MATCHED se obvykle používá k UPDATE;WHEN NOT MATCHED BY SOURCE se obvykle používá k DELETE , ale tady je nepotřebujeme.
Tato spletitá forma MERGE je ekvivalentní jednoduchému INSERT ,ale na rozdíl od jednoduchého INSERT jeho OUTPUT klauzule umožňuje odkazovat na sloupce, které potřebujeme. Umožňuje načíst sloupce ze zdrojových i cílových tabulek, čímž se ukládá mapování mezi starými existujícími ID a novými ID generovanými IDENTITY .
Ukázková data
INSERT INTO [dbo].[StageDetail]
([StageNUmber]
,[TypeOfStage]
,[Distance])
VALUES
('sn01','t1','D1'),
('sn02','t2','D2'),
('sn03','t3','D3');
INSERT INTO [dbo].[StageDetailItem]
([StageDetailID]
,[Road]
,[CostPer])
VALUES
(1,'r1_1','C11'),
(1,'r1_2','C12'),
(1,'r1_3','C13'),
(1,'r1_4','C14'),
(1,'r1_5','C15'),
(2,'r2_1','C16'),
(2,'r2_2','C17'),
(2,'r2_3','C18'),
(2,'r2_4','C19'),
(2,'r2_5','C20'),
(3,'r3_1','C21'),
(3,'r3_2','C22'),
(3,'r3_3','C23'),
(3,'r3_4','C24'),
(3,'r3_5','C25');
Dotaz
Deklarujte proměnnou tabulky (nebo dočasnou tabulku), která bude obsahovat mapování mezi starými a novými ID.
DECLARE @T TABLE(OldStageDetailID int, NewStageDetailID int);
Nejprve vytvořte kopii řádků z StageDetail tabulka, která si pamatuje mapování ID v proměnné table.
MERGE INTO [dbo].[StageDetail]
USING
(
SELECT [StageDetailID],[StageNUmber],[TypeOfStage],[Distance]
FROM [dbo].[StageDetail]
) AS Src
ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT ([StageNUmber],[TypeOfStage],[Distance])
VALUES
(Src.[StageNUmber]
,Src.[TypeOfStage]
,Src.[Distance])
OUTPUT
Src.[StageDetailID] AS OldStageDetailID
,inserted.[StageDetailID] AS NewStageDetailID
INTO @T(OldStageDetailID, NewStageDetailID)
;
Poté zkopírujte řádky z StageDetailItem pomocí nových StageDetailIDs .
INSERT INTO [dbo].[StageDetailItem]
([StageDetailID]
,[Road]
,[CostPer])
SELECT
T.[NewStageDetailID]
,[dbo].[StageDetailItem].[Road]
,[dbo].[StageDetailItem].[CostPer]
FROM
[dbo].[StageDetailItem]
INNER JOIN @T AS T ON T.OldStageDetailID = [dbo].[StageDetailItem].StageDetailID
;
Výsledek
SELECT * FROM [dbo].[StageDetail]
+---------------+-------------+-------------+----------+
| StageDetailID | StageNUmber | TypeOfStage | Distance |
+---------------+-------------+-------------+----------+
| 1 | sn01 | t1 | D1 |
| 2 | sn02 | t2 | D2 |
| 3 | sn03 | t3 | D3 |
| 4 | sn01 | t1 | D1 |
| 5 | sn02 | t2 | D2 |
| 6 | sn03 | t3 | D3 |
+---------------+-------------+-------------+----------+
.
SELECT * FROM [dbo].[StageDetailItem]
+-------------------+---------------+------+---------+
| StageDetailItemID | StageDetailID | Road | CostPer |
+-------------------+---------------+------+---------+
| 1 | 1 | r1_1 | C11 |
| 2 | 1 | r1_2 | C12 |
| 3 | 1 | r1_3 | C13 |
| 4 | 1 | r1_4 | C14 |
| 5 | 1 | r1_5 | C15 |
| 6 | 2 | r2_1 | C16 |
| 7 | 2 | r2_2 | C17 |
| 8 | 2 | r2_3 | C18 |
| 9 | 2 | r2_4 | C19 |
| 10 | 2 | r2_5 | C20 |
| 11 | 3 | r3_1 | C21 |
| 12 | 3 | r3_2 | C22 |
| 13 | 3 | r3_3 | C23 |
| 14 | 3 | r3_4 | C24 |
| 15 | 3 | r3_5 | C25 |
| 16 | 4 | r1_1 | C11 |
| 17 | 4 | r1_2 | C12 |
| 18 | 4 | r1_3 | C13 |
| 19 | 4 | r1_4 | C14 |
| 20 | 4 | r1_5 | C15 |
| 21 | 5 | r2_1 | C16 |
| 22 | 5 | r2_2 | C17 |
| 23 | 5 | r2_3 | C18 |
| 24 | 5 | r2_4 | C19 |
| 25 | 5 | r2_5 | C20 |
| 26 | 6 | r3_1 | C21 |
| 27 | 6 | r3_2 | C22 |
| 28 | 6 | r3_3 | C23 |
| 29 | 6 | r3_4 | C24 |
| 30 | 6 | r3_5 | C25 |
+-------------------+---------------+------+---------+