2014-02-13 52 views
0

我在兩個表中有一些父/子數據。我需要將父行復制回父表中,但也要將子行復製爲創建的新行的子行。 我一直在搜索這個網站和谷歌,但只能找到來自甲骨文的例子或使用XML(或有很多關於不可靠的警告),所以我在這裏發佈一個完整的易於參考的解決方案。重複的父/子數據

採取以下代碼(SqlFiddle):

DECLARE @tbl_person TABLE 
    (
    ID int IDENTITY(1,1), 
    person nvarchar(20) 
    ); 

DECLARE @tbl_drinks TABLE 
    (
    ID int IDENTITY(1,1), 
    personID int, 
    drink nvarchar(20) 
    ); 

DECLARE @i int; 
INSERT INTO @tbl_person (person) VALUES ('Bob'); 
SET @i = SCOPE_IDENTITY(); 
INSERT INTO @tbl_drinks (personID, drink) VALUES (@i, 'Beer'); 
INSERT INTO @tbl_person (person) VALUES ('Wendy'); 
SET @i = SCOPE_IDENTITY(); 
INSERT INTO @tbl_drinks (personID, drink) VALUES (@i, 'Champage'); 
INSERT INTO @tbl_drinks (personID, drink) VALUES (@i, 'Water'); 
INSERT INTO @tbl_person (person) VALUES ('Mike'); 
SET @i = SCOPE_IDENTITY(); 
INSERT INTO @tbl_drinks (personID, drink) VALUES (@i, 'Beer'); 
INSERT INTO @tbl_drinks (personID, drink) VALUES (@i, 'Lemonade'); 

SELECT * FROM @tbl_person; 
SELECT * FROM @tbl_drinks; 

這會產生這樣的輸出:

ID   person 
----------- -------------------- 
1   Bob 
2   Wendy 
3   Mike 

ID   personID drink 
----------- ----------- -------------------- 
1   1   Beer 
2   2   Champage 
3   2   Water 
4   3   Beer 
5   3   Lemonade 

我知道如何輕鬆地複製一個人加上他們的飲料,但不是多人。假設我需要複製鮑勃和溫迪我需要的輸出:

ID   person 
----------- -------------------- 
1   Bob 
2   Wendy 
3   Mike 
4   Bob 
5   Wendy 

ID   personID drink 
----------- ----------- -------------------- 
1   1   Beer 
2   2   Champage 
3   2   Water 
4   3   Beer 
5   3   Lemonade 
6   4   Beer 
7   5   Champagne 
8   5   Water 

我無法弄清楚如何將新老父ID列爲了得到孩子的數據進行比較。

回答

1

問題是INSERT並沒有真正的「從表」,您可以在OUTPUT子句中引用。但是你可以達到同樣的用MERGE聲明:

declare @tbl_IDmap table (newID int, oldID int) 

merge @tbl_person as target 
using (
    select ID, person from @tbl_person where ID in (1,2) 
) as source(ID, person) 
on 1=0 
when not matched then 
    insert (person) values(person) 
    output inserted.ID, source.ID into @tbl_IDmap; 

然後用新的ID重複飲料:

insert into @tbl_drinks(personID, drink) 
select m.newID, d.drink 
from @tbl_drinks d 
inner join @tbl_IDmap m 
    on m.oldID = d.personID 

這是你的SqlFiddle更新。

+0

什麼是'目的)作爲源(ID,人)'而不是')作爲source'。我從閱讀MSDN假設,這給了'源'中的列的別名,但在這種情況下不需要(查詢沒有它)? – EvilDr

+1

你說得對,在這種情況下你不需要別名。 – TomT

0

決定添加一些額外的解決方案(並且已經考慮了這個晚上的大部分時間!)我發佈了一個不使用MERGE的附加解決方案,希望能夠幫助用戶使用舊版本的SQL。它比@TTT的建議更詳細,但工作正常。

SQLFiddle

-- Gather the people we need to copy 
DECLARE @tbl_IdsToCopy TABLE 
    (
    [counter] int IDENTITY(1,1), 
    [existingId] int 
    ); 
INSERT INTO @tbl_IdsToCopy (existingId) VALUES (1),(2); -- Bob & Wendy 

-- Table to save new person ID's 
DECLARE @tbl_newIds TABLE 
    (
    [counter] int IDENTITY(1,1), 
    [newId] int 
    ); 

-- Create new people and save their new Id's 
INSERT INTO @tbl_person 
    (
    person 
    ) 
OUTPUT 
    INSERTED.ID 
INTO 
    @tbl_newIds 
    (
    [newId] 
    ) 
SELECT 
    p.person 
FROM 
    @tbl_person p INNER JOIN 
    @tbl_IdsToCopy c ON c.existingId = p.ID 
ORDER BY 
    c.[counter]; -- use counter to preserve ordering 

-- map the old ID's to the new ID's and find the drinks for the old ID's 
INSERT INTO @tbl_drinks 
    (
    personID, 
    drink 
    ) 
SELECT 
    n.[newId], 
    d.drink 
FROM 
    @tbl_IdsToCopy c INNER JOIN 
    @tbl_newIds n ON c.[counter] = n.[counter] INNER JOIN -- <-- map the old person ID to the new person Id 
    @tbl_drinks d ON d.personID = c.existingId;    -- <-- find the drinks of the old person Id 

-- Results 
SELECT 
    p.ID, 
    p.person, 
    d.ID, 
    d.drink 
FROM 
    @tbl_person p INNER JOIN 
    @tbl_drinks d ON d.personID = p.ID; 
+1

'[counter] int IDENTITY(1,1)' – TomT