Stored procedures 在SQL Server 2008 R2中更新合并语句中插入的记录

Stored procedures 在SQL Server 2008 R2中更新合并语句中插入的记录,stored-procedures,sql-server-2008-r2,merge-statement,Stored Procedures,Sql Server 2008 R2,Merge Statement,我的SQL Server 2008 R2存储过程中有以下代码。在该存储过程中,我将一个城市及其家人和人员复制到另一个城市 在这里,我在@FamilyIdMap中维护了家族的源id和目标id 左栏表示代码行号 它给出如下输出: 源表 PersonID FamilyID PersonName ParentID 1 1 ABC Null 2 1 Son of ABC 1 3

我的SQL Server 2008 R2存储过程中有以下代码。在该存储过程中,我将一个城市及其家人和人员复制到另一个城市

在这里,我在
@FamilyIdMap
中维护了家族的源id和目标id

左栏表示代码行号

它给出如下输出:

源表

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  6 <-- ParentID should be updated
8           1           Son of ABC  6 <--
9           2           XYZ         NULL
10          2           Son of XYZ  9 <--
目标表(使用上述给定代码从源表复制)

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 <--
我知道问题出在代码的第10行

10>     ParentID) OUTPUT

但是我应该用
ParentID
替换什么来更新它呢?提前感谢。

在SQL Server 2008R2中,您要做的事情不能一步完成。 更新ParentId必须是第二步,因为您无法访问插入另一行的结果所在的一行中的输出值。但是,您已经在为第二步收集信息。所以,您只需要添加一个简单的更新

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表。我也清理了你原来的合并一点。它现在使用@FamilyIdMap表作为选择行的手段,而不是再次加入dbo.Family表。如果仅在一小部分族上运行此操作,则速度应该更快。如果您有很多族,并将它们全部复制,那么再次使用dbo.Family表可能会更快

最终更新仅更新Person表中的新行(所有新创建的Personid都可以在@PersonIdMap表的TargetId列中找到),使用@PersonIdMap表中的信息将旧的ParentId值更改为新的ParentId值


我没有包括事务管理,但至少合并dbo.Person和以下更新dbo.Person应该在同一事务中执行。

它按预期工作,非常感谢您的时间和努力:)
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;