重复的父/子数据

时间:2014-02-13 15:56:46

标签: sql-server tsql sql-server-2012

我在两个表中有一些父/子数据。我需要将父行复制回父表,但是还要将子行复制为创建的新行的子行。 我一直在搜索这个网站和谷歌,但只能找到Oracle的例子或使用XML的例子(或者有很多关于不可靠的警告),所以我在这里发布一个完整的易于参考的解决方案。< / p>

采用以下代码(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

我知道如何轻松复制一个人加上他们的饮料,但不是多人。假设我需要复制Bob和Wendy,我需要得到这个输出:

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列以获取子数据。

2 个答案:

答案 0 :(得分:3)

问题是INSERT实际上没有可以在OUTPUT子句中引用的“from table”。但是你可以用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已更新。

答案 1 :(得分:0)

决定添加一些额外的解决方案(并且在晚上的大部分时间都考虑过了!)我发布了一个不使用MERGE的其他解决方案,希望能够帮助用户使用旧版本的SQL。它比@ TomT的建议更冗长,但工作正常。

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;