0

SQL Server2008R2ストアドプロシージャに次のコードがあります。そのストアドプロシージャでは、ある都市を家族や人と一緒に別の都市にコピーしています。

ここでは、ファミリのソースIDとターゲットIDをで維持してい@FamilyIdMapます。

左の列はコード行番号を示します。

-- 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しかし、それを更新するには何に置き換える必要がありますか?前もって感謝します。

4

1 に答える 1

2

SQL Server 2008R2では、実行しようとしていることを1つの手順で実行することはできません。別の行の挿入の結果である1つの行のOUTPUT値にアクセスできないため、ParentIdの更新は2番目のステップである必要があります。ただし、すでに2番目のステップの情報を収集しています。したがって、簡単な更新を追加するだけです。

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も少しクリーンアップしました。現在、dbo.Familyテーブルに再度参加する代わりに、行を選択する手段として@FamilyIdMapテーブルを使用しています。ファミリの小さなサブセットでのみこれを実行する場合、これはより高速になるはずです。家族がたくさんいて、それらをすべてコピーする場合は、dbo.Familyテーブルに再度反対する方が速い場合があります。

最終的なUPDATEは、Personテーブルの新しい行のみを更新し(新しく作成されたすべてのPersonIdは@PersonIdMapテーブルのTargetId列にあります)、@PersonIdMapテーブルの情報を使用して古いParentId値を新しいParentId値に変更します。

トランザクション管理は含めませんでしたが、少なくともMERGEdbo.Personと次のUPDATEdbo.Personは同じトランザクション内で実行する必要があります。

于 2012-12-10T22:30:26.320 に答える