1

SQL Server 2008 を使用しています。テーブル内の重複行を削除しようとしています。関連するテーブルと列を次に示します。

ItemTable
----------
Id - autoincrement, PK
ItemLabel - the actual identifier of the items


Linktable
----------
Id - autoincrement, PK
ItemId - the Id from ItemTable
RelatedItemId - the Id from RelatedItemTable


RelatedItemTable
------
no need to touch this with the query..

したがって、リンク テーブルにはアイテムの実際の ID は含まれませんが、2 つのテーブルからの実行中の行番号が含まれます。

達成する必要があること: ItemTable には、重複する ItemLabel を持つ行が含まれています。もう 1 つはリンク テーブルに (Id 列の値と共に) リストされ、もう 1 つはそうではありません。ItemTable から、リンクされていないものを削除する必要があります。count と group by を使用して重複行を選択する方法は知っていますが、リンク テーブルに存在しない行のみを削除する方法を理解できませんでした。ItemTable には、関係のないアイテムの重複も含まれます。そのうちの 1 つを残す必要があります (どちらでもかまいません)。

http://www.sqlfiddle.com/#!3/9d181これは、ダミー データを使用した SQL フィドルです。

PSリンクテーブルが実際のID(PKされる可能性がある)の代わりに実行中のIDを使用する理由を尋ねないでください...それはレガシーシステムです。

4

2 に答える 2

0

を使用して両方のテーブルを結合しますLEFT JOIN。明らかに、存在しないItemTable.ID場合はnull値がオンになり、これは句Linktable.ItemIDでフィルタリングされます。WHERE

DELETE  a
FROM    ItemTable a
        LEFT JOIN Linktable b
            ON a.ID = b.ItemID
WHERE   b.ItemID IS NULL
于 2013-03-11T08:42:26.193 に答える
0

これを試してください:

DELETE t
OUTPUT deleted.*
FROM    ItemTable t
JOIN    (
 SELECT DENSE_RANK() OVER (PARTITION BY ItemLabel ORDER BY lt.ItemID DESC, it.id) num
        , it.Id
 FROM   ItemTable it
 LEFT JOIN 
        LinkTable lt ON
        lt.ItemId = it.id
) t2 ON t2.Id = t.Id
WHERE num > 1

SQL フィドル

上記のアプローチはあなたの状況に適していますが、より読みやすく、より詳細に制御し、より良い概要を把握できるアプローチをお勧めします。これは、各ステップを分析およびテストできるマルチステップ アプローチです。

-- get ItemLabels of duplicate records
SELECT  ItemLabel
INTO    #Duplicate_ItemLabels
FROM    ItemTable it
GROUP BY
        it.ItemLabel
HAVING  COUNT(*) > 1

-- get ItemLabels of duplicate records that have at least one record related to LinkTable
SELECT  *
INTO    #Duplicate_ItemLabels_Related_To_LinkTable
FROM    #Duplicate_ItemLabels d1
WHERE   EXISTS
(
        SELECT  *
        FROM    ItemTable it
        JOIN    Linktable lt ON 
                lt.ItemID = it.ID
        WHERE   it.ItemLabel = d1.ItemLabel
)

-- get ItemLabels of duplicate records that don't have any records related to LinkTable
SELECT  ItemLabel
INTO    #Duplicate_ItemLabels_NOT_Related_To_LinkTable
FROM    #Duplicate_ItemLabels
EXCEPT
SELECT  ItemLabel
FROM    #Duplicate_ItemLabels_Related_To_LinkTable

-- delete unwanted records for ItemLabels that have records related to linkTable
DELETE  it
OUTPUT  deleted.*
FROM    ItemTable it
JOIN    #Duplicate_ItemLabels_Related_To_LinkTable dup ON
        dup.ItemLabel = it.ItemLabel
WHERE   NOT EXISTS
(
        SELECT  *
        FROM    Linktable lt
        WHERE   lt.ItemID = it.ID
)

-- delete unwanted records for ItemLabels that don't have any records related to linkTable
DELETE  it
OUTPUT  deleted.*
FROM    ItemTable it
JOIN    #Duplicate_ItemLabels_NOT_Related_To_LinkTable dup ON
        dup.ItemLabel = it.ItemLabel
JOIN    
(
        -- records deleted will be all those that have ID greater than the smallest ID for this ItemLabel
        SELECT  ItemLabel
                , MIN(ID) ID
        FROM    ItemTable dup
        GROUP BY
                dup.ItemLabel
)       gr ON
        gr.ID < it.ID
AND     gr.ItemLabel = dup.ItemLabel

-- if after these DELETEs there are still duplicate records, it 
-- means that there are records for same ItemLabel with 
-- different ID and all of them are related to LinkTable

簡単に変更し、結果をテストし、削除するレコードを操作できます。SQL Fiddleを作成し、データのさまざまなサンプルを入れて、データがどのように処理されているかを確認できるようにしました。

2 番目のアプローチのデータをサンプリングするために、複数のレコードが関連してItemTableいる同じレコードを追加しました(任意に削除されるレコードはありません)。ItemLabelIDLinkTable

于 2013-03-11T08:50:29.317 に答える