What you are trying to do cannot be done in a single step in SQL Server 2008R2. Updating the ParentId has to be a second step, as you cannot access OUTPUT values in one row that where the result of the insert of another row. However, you are already collecting the information for the second step. So, you just need to add a simple update.
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;
I did add code to create and fill the @FamilyIdMap table. I also cleaned up your original MERGE a little. It is now using the @FamilyIdMap table as a means to select the rows instead of joining to the dbo.Family table again. If you run this only on a small subset of families this should be faster. If you have a lot of families and you copy them all, going against the dbo.Family table again might be faster.
The final UPDATE updates only new rows in the Person table (all newly created PersonIds can be found in the TargetId column of the @PersonIdMap table), changing old ParentId values to new ParentId values using the information in the @PersonIdMap table.
I did not include transaction management, but atleast the MERGE dbo.Person and the following UPDATE dbo.Person should be executed inside the same transaction.