2014-02-13 49 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