2012-12-04 60 views
0

我的SQL Server 2008 R2存儲過程中有以下代碼。在這個存儲過程中,我正在將一個城市複製到另一個城市,並與其家人和人物一起。在SQL Server 2008 R2中的MERGE語句中更新插入的記錄

這裏我在@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來代替它來更新它?提前致謝。

回答

2

您嘗試執行的操作無法在SQL Server 2008 R2的單個步驟中完成。 更新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表中的新行(所有新創建的PersonIds都可以在@PersonIdMap表的TargetId列中找到),使用@PersonIdMap表中的信息將舊的ParentId值更改爲新的ParentId值。

我沒有包括事務管理,但是至少MERGE dbo.Person和下面的UPDATE dbo.Person應該在同一個事務中執行。

+0

它按預期工作,非常感謝您的時間和精力:) –

相關問題