删除不同的行

时间:2011-08-02 17:30:14

标签: sql sql-server greatest-n-per-group

我有一个具有唯一非聚集索引的表,并且此索引中列出了4列。我想更新表中的大量行。如果我这样做,它们将不再是不同的,因此更新因索引而失败。

我想要禁用索引,然后删除最早的重复行。到目前为止,这是我的查询:

SELECT t.itemid, t.fieldid, t.version, updated
FROM dbo.VersionedFields w
inner JOIN
(
    SELECT itemid, fieldid, version, COUNT(*) AS QTY
    FROM dbo.VersionedFields
    GROUP BY itemid, fieldid, version
    HAVING COUNT(*) > 1
) t 
on w.itemid = t.itemid and w.fieldid = t.fieldid and w.version = t.version

内部联接内部的选择返回我们想要删除的正确数量的记录,但是将它们分组以便实际上有两倍的数量。

加入后会显示所有记录,但我想要删除的是最早的记录吗?

如何做到这一点?

4 个答案:

答案 0 :(得分:10)

如果您说SQL(结构化查询语言),但真正意味着SQL Server(Microsoft relatinonal数据库系统),如果您使用的是SQL Server 2005或更新版本,则可以使用为此目的的CTE(通用表格表达式)。

使用此CTE,您可以按照某些条件对数据进行分区 - 即ItemId(或列的组合) - 并为每个分区的所有行启用SQL Server编号,按顺序排列一些其他标准 - 即可能version(或其他一些列)。

所以尝试这样的事情:

;WITH PartitionedData AS
(
    SELECT 
       itemid, fieldid, version, 
       ROW_NUMBER() OVER(PARTITION BY ItemId ORDER BY version DESC) AS 'RowNum'
    FROM dbo.VersionedFields
)
DELETE FROM PartitionedData
WHERE RowNum > 1

基本上,您按照某些条件对数据进行分区并为每个分区编号,每个新分区从1开始,按其他一些条件(例如日期或版本)排序。

因此,对于数据的每个“分区”,“最新”条目具有RowNum = 1,并且属于同一分区的任何其他条目(通过具有相同的partitino值)将具有从2到高达的顺序编号值。但是该分区中有很多行。

如果你只想保留最新的条目 - 删除RowNum大于1的任何东西,你就完成了!

答案 1 :(得分:4)

SQL Server 2005及以上:

WITH    q AS
        (
        SELECT  *,
                ROW_NUMBER() OVER (PARTITION BY itemid, fieldid, version ORDER BY updated DESC) AS rn
        FROM    versionedFields
        )
DELETE
FROM    q
WHERE   rn > 1

答案 2 :(得分:0)

尝试类似:

DELETE FROM dbo.VersionedFields w WHERE w.version < (SELECT MAX(version) FROM dbo.VersionedFields)

当然,你想要将MAX(版本)限制为你想要删除的字段的版本。

答案 3 :(得分:0)

您可能需要查看this Stack Overflow answer(删除较早的重复行)。

本质上,该技术使用分组(或可选地,窗口化)来查找组的最小id值以便将其删除。删除值&lt;&gt;的行可能更准确。 max(行标识符)。

所以:

  1. 删除唯一索引
  2. 加载数据
  3. 使用分组机制删除数据(理想情况是在事务中,以便在出现错误时可以回滚),然后提交
  4. 重新创建索引。
  5. 请注意,在大表上重新创建索引可能需要很长时间。