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,而是两个表的运行行号

需要实现的目标:ItemTable 包含具有重复 ItemLabel 的行,其中另一个列在链接表中(带有 Id 列的值),而另一个则没有。必须从 ItemTable 中删除未链接的那些。我知道如何使用 count 和 group by 选择重复的行,但无法弄清楚如何仅删除链接表中不存在的行。ItemTable 还包含没有关系的项目的重复项,其中一个必须保留(不管哪个)。

http://www.sqlfiddle.com/#!3/9d181这是一个带有虚拟数据的 SQL 小提琴。

PS不要问为什么链接表使用运行id而不是实际id(可能是PK'd)......这是一个遗留系统。

4

2 回答 2

0

使用 连接两个表LEFT JOIN。显然不存在ItemTable.ID将具有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,我在其中放置了不同的数据样本,以便您可以看到它是如何处理的。

为了对第二种方法的数据进行采样,我还添加了记录,ItemTable其中您有相同但ItemLabel不同ID的记录有多个相关LinkTable(没有一个被任意删除)。

于 2013-03-11T08:50:29.317 回答