我在两个表中有一些父/子数据。我需要将父行复制回父表,但是还要将子行复制为创建的新行的子行。 我一直在搜索这个网站和谷歌,但只能找到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列以获取子数据。
答案 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的建议更冗长,但工作正常。
-- 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;