2

重複した項目のリストが長い表があります。私はそれらをすべて1つのレコードに統合するためのストアドプロシージャに取り組んでいます。重複した項目のそれぞれには、削除するか、結果のレコードを指すようにキーを変更する必要があるいくつかの子表があります。私のテーブルにはIDがありますが、ReadableIdentifierは重複排除に必要な列です。重複する行と依存関係をカーソルなしで削除する

Id | ReadableIdentifier | Name  | UpdatedOn 
1 | ABC1234   | Product X | 2014-04-25 16:00:08.000 
2 | ABC1234   | Product X | 2014-04-28 16:00:08.000 
3 | ABC1234   | Product X | 2014-04-21 16:00:08.000 
4 | ABDD9945   | Widget R | 2014-04-25 16:00:08.000 
5 | ABDD9945   | Widget R | 2014-04-25 18:45:08.000 

ご覧のとおり、レコード1〜3は異なるIDと更新日の重複したものです。 4-5と同じです。私はこれらを1つのレコードに統合し、最新のUpdatedOn日付を持つレコードを優先する必要があります。

最終目標(子テーブルを表示されない):

Id | ReadableIdentifier | Name  | UpdatedOn 
2 | ABC1234   | Product X | 2014-04-28 16:00:08.000 
5 | ABDD9945   | Widget R | 2014-04-25 18:45:08.000 

私はこれを行うにはCURSORを使用していますが、よりよい解決策がある場合は疑問に思って。

DECLARE dupeCursor CURSOR 
    FAST_FORWARD 
FOR 
    WITH Counts AS (
     SELECT 
      COUNT(1) Count, 
      ReadableIdentifier 
     FROM dbo.Item WITH (NOLOCK) 
     WHERE ReadableIdentifier IS NOT NULL 
     GROUP BY ReadableIdentifier) 
    SELECT 
     Counts.Count, 
     Counts.ReadableIdentifier, 
     Counts.CompanyId 
    FROM 
     Counts 
    WHERE Counts.Count > 1; 

OPEN dupeCursor; 
DECLARE @readableId VARCHAR(50); 
DECLARE @itemToPersistId INT, @itemToDeleteId INT; 
FETCH NEXT FROM dupeCursor INTO @readableId; 

WHILE @@FETCH_STATUS = 0 
BEGIN 

    WITH V AS (
     SELECT Id, ROW_NUMBER() OVER (PARTITION BY ReadableId ORDER BY UpdatedOn DESC) as Row 
     FROM dbo.Item WITH (NOLOCK) WHERE ReadableId = @readableId 
    ) 
    SELECT @itemToPersistId = Id 
    FROM V 
    WHERE V.Row = 1 

    CREATE TABLE #itemsToDelete (Id UNIQUEIDENTIFIER) 
    INSERT INTO #itemsToDelete 
    SELECT Id 
    FROM dbo.Item WITH (NOLOCK) 
    WHERE ReadableId = @readableId AND Id != @itemToPersistId; 

    --UPDATE CHILDREN TABLES 
    DELETE FROM dbo.ItemDetails WHERE ItemId IN (SELECT Id FROM #itemsToDelete); 

    UPDATE dbo.ItemPurchases SET ItemId = @itemToPersistId 
    WHERE ItemId IN (SELECT Id FROM #itemsToDelete); 

    UPDATE dbo.PurchaseOrders SET ItemId = @itemToPersistId 
    WHERE ItemId IN (SELECT Id FROM #itemsToDelete); 

    DELETE FROM dbo.ItemMetadata WHERE ItemId IN (SELECT Id FROM #itemsToDelete); 

    --delete Duplicated Items 
    DELETE FROM dbo.Item WHERE Id IN (SELECT Id FROM #itemsToDelete); 

    DROP TABLE #itemsToDelete 

    FETCH NEXT FROM dupeCursor INTO @readableId; 
END 

CLOSE dupeCursor; 
DEALLOCATE dupeCursor; 

私はカーソルが最も可能性の高い問題であると認識、しかし、私は1つを使用せずに子テーブルのすべての更新については移動するかどうかはわかりません。

答えて

1

は、[OK]を私は子テーブルのためにこれをテストするためのデータを持っていけないが、それは動作するはずです:

WITH V 
    AS (SELECT *, 
       ROW_NUMBER() OVER(PARTITION BY ReadableId ORDER BY UpdatedOn DESC) AS Row 
     FROM dbo.Item WITH (NOLOCK)) 
    SELECT * 
    INTO #itemsToDelete 
    FROM V; 

--UPDATE CHILDREN TABLES 
DELETE FROM dbo.ItemDetails 
WHERE ItemId IN 
(
    SELECT Id 
    FROM #itemsToDelete 
    WHERE Row > 1 
); 
UPDATE IP 
    SET 
     IP.ItemId = itk.ID 
FROM dbo.ItemPurchases AS IP 
    INNER JOIN #itemsToDelete AS itd ON IP.ItemId = itd.ID 
             AND itd.Row > 1 
    INNER JOIN #itemsToDelete AS itk ON itk.ReadableIdentifier = itd.ReadableIdentifier 
             AND itk.Row = 1 
             AND itd.Row > 1; 
UPDATE po 
    SET 
     po.ItemId = itk.ID 
FROM dbo.PurchaseOrders AS po 
    INNER JOIN #itemsToDelete AS itd ON po.ItemId = itd.ID 
             AND itd.Row > 1 
    INNER JOIN #itemsToDelete AS itk ON itk.ReadableIdentifier = itd.ReadableIdentifier 
             AND itk.Row = 1 
             AND itd.Row > 1; 
DELETE FROM dbo.ItemMetadata 
WHERE ItemId IN 
(
    SELECT Id 
    FROM #itemsToDelete 
    WHERE Row > 1 
); 

--delete Duplicated Items 
DELETE FROM dbo.Item 
WHERE Id IN 
(
    SELECT Id 
    FROM #itemsToDelete 
    WHERE Row > 1 
); 
+0

右、私はこれはすでに行っています。 CURSORを使わずに子テーブルのUPDATE/DELETEを実行するにはどうすればいいですか? – gwin003

+0

はIdですが、他のテーブルの外部キーですか? –

+0

はい、私の質問のステートメントを参照してください。 – gwin003

関連する問題