我的SQL Server 2008 R2存储过程中有以下代码。在那个存储过程中,我将一个城市与其家人和人一起复制到另一个城市。
我在@FamilyIdMap
中维护家庭的来源和目标ID。
左列表示代码行号
-- Copy Person
1> DECLARE @PersonIdMap table (TargetId int, SourceId int)
2> MERGE Person as PersonTargetTable
3> USING (SELECT PersonID, FamilyID, PersonName, ParentID FROM Person
4> WHERE FamilyID in (SELECT FamilyID from Family where FamilyName like '%DA%'))
5> AS PersonSourceTable ON (0=1)
6> WHEN NOT MATCHED THEN
7> INSERT(FamilyID, PersonName, ParentID)
8> VALUES
9> ((SELECT TOP 1 TargetID from @FamilyIdMap WHERE SourceID=FamilyID),PersonName,
10> ParentID) OUTPUT
11> INSERTED.PersonID, PersonSourceTable.PersonID
12> INTO @PersonIdMap;
它输出如下:
来源表
PersonID FamilyID PersonName ParentID
1 1 ABC Null
2 1 Son of ABC 1
3 1 Son of ABC 1
4 2 XYZ NULL
5 2 Son of XYZ 4
目标表(使用上面给出的代码从源表复制)
PersonID FamilyID PersonName ParentID
6 1 ABC Null
7 1 Son of ABC 1 <-- ParentID Remains as it is
8 1 Son of ABC 1 <--
9 2 XYZ NULL
10 2 Son of XYZ 4 <--
以上输出中的问题是它没有更新parentID
,我希望输出为:
预期目标表
PersonID FamilyID PersonName ParentID
6 1 ABC Null
7 1 Son of ABC 6 <-- ParentID should be updated
8 1 Son of ABC 6 <--
9 2 XYZ NULL
10 2 Son of XYZ 9 <--
我知道问题出在代码第10行
10> ParentID) OUTPUT
但我应该用ParentID
替换它来更新它?提前谢谢。
答案 0 :(得分:2)
您尝试执行的操作无法在SQL Server 2008R2中的单个步骤中完成。 更新ParentId必须是第二步,因为您无法访问另一行插入结果的行中的OUTPUT值。但是,您已经在收集第二步的信息。所以,你只需要添加一个简单的更新。
IF OBJECT_ID('dbo.Person') IS NOT NULL DROP TABLE dbo.Person;
IF OBJECT_ID('dbo.Family') IS NOT NULL DROP TABLE dbo.Family;
CREATE TABLE dbo.Family(FamilyID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, FamilyName NVARCHAR(60));
CREATE TABLE dbo.Person(PersonID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, FamilyID INT REFERENCES dbo.Family(FamilyID), PersonName NVARCHAR(60), ParentID INT);
INSERT INTO dbo.Family(FamilyName) VALUES
('DA1'),
('DA2');
INSERT INTO dbo.Person(FamilyID, PersonName, ParentID) VALUES
(1, 'ABC', NULL),
(1, 'Son of ABC', 1),
(1, 'Son of ABC', 1),
(2, 'XYZ', NULL),
(2, 'Son of XYZ', 4 );
DECLARE @FamilyIdMap table (TargetId int, SourceId int)
MERGE dbo.Family tf
USING (SELECT * FROM dbo.Family WHERE FamilyName like '%DA%') AS sf
ON 1=0
WHEN NOT MATCHED THEN
INSERT (FamilyName)
VALUES(sf.FamilyName)
OUTPUT INSERTED.FamilyID, sf.FamilyID
INTO @FamilyIdMap;
DECLARE @PersonIdMap table (TargetId int, SourceId int)
MERGE dbo.Person as tp
USING (SELECT p.PersonID, p.FamilyID, p.PersonName, p.ParentID, fm.SourceId,fm.TargetId FROM Person AS p
INNER JOIN @FamilyIdMap AS fm
ON p.FamilyID = fm.SourceId) AS sp
ON (0=1)
WHEN NOT MATCHED THEN
INSERT(FamilyID, PersonName, ParentID)
VALUES
(sp.TargetId,PersonName, ParentID) OUTPUT
INSERTED.PersonID, sp.PersonID
INTO @PersonIdMap;
UPDATE p SET
ParentID = pm.TargetId
FROM dbo.Person AS p
JOIN @PersonIdMap pm
ON pm.SourceId = p.ParentID
WHERE EXISTS(SELECT 1 FROM @PersonIdMap pmf WHERE pmf.TargetId = p.PersonID);
SELECT * FROM dbo.Family;
SELECT * FROM @FamilyIdMap;
SELECT * FROM dbo.Person;
SELECT * FROM @PersonIdMap;
我确实添加了代码来创建和填充@FamilyIdMap表。我还清理了你原来的MERGE。它现在使用@FamilyIdMap表作为选择行的方法,而不是再次连接到dbo.Family表。如果你只在一小部分家庭上运行它,这应该更快。如果你有很多家庭并将它们全部复制,那么再次反对dbo.Family表可能会更快。
最后的UPDATE只更新Person表中的新行(所有新创建的PersonId都可以在@PersonIdMap表的TargetId列中找到),使用@PersonIdMap表中的信息将旧的ParentId值更改为新的ParentId值。
我没有包含事务管理,但至少有MERGE dbo.Person和以下UPDATE dbo.Person应该在同一个事务中执行。