删除非不同行
Posted
技术标签:
【中文标题】删除非不同行【英文标题】:Deleting non distinct rows 【发布时间】:2011-08-02 17:30:13 【问题描述】:我有一个具有唯一非聚集索引的表,其中 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
内部连接中的选择返回我们想要删除的正确数量的记录,但将它们分组,因此实际上有两倍的数量。
加入后它会显示所有记录,但我只想删除最旧的记录?
如何做到这一点?
【问题讨论】:
【参考方案1】:如果您说SQL
(结构化查询语言),但实际上是指SQL Server
(Microsoft 关系数据库系统),并且如果您使用的是 SQL Server 2005 或更新版本,则可以使用 CTE(通用表表达式)用于此目的。
使用此 CTE,您可以按某些标准对数据进行分区 - 即您的 ItemId
(或列的组合) - 并让 SQL Server 为每个分区从 1 开始为您的所有行编号,按其他一些排序标准 - 即可能是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,属于同一分区的任何其他条目(通过具有相同的分区值)将具有从 2 到 2 的顺序编号值无论该分区中有多少行。
如果您只想保留最新条目 - 删除 RowNum 大于 1 的任何内容即可!
【讨论】:
【参考方案2】: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
【讨论】:
【参考方案3】:尝试类似:
DELETE FROM dbo.VersionedFields w WHERE w.version < (SELECT MAX(version) FROM dbo.VersionedFields)
当然,您希望将 MAX(version) 限制为仅要删除的字段的版本。
【讨论】:
【参考方案4】:您可能需要查看this Stack Overflow answer(删除前面的重复行)。
本质上,该技术使用分组(或可选地,窗口化)来查找组的最小 id 值以将其删除。删除值 max(row identifier) 的行可能更准确。
所以:
-
删除唯一索引
加载数据
使用分组机制删除数据(最好是在一个事务中,这样出错时可以回滚),然后提交
重新创建索引。
请注意,在大表上重新创建索引可能需要很长时间。
【讨论】:
marc_s 的解决方案是一种优雅的方式。以上是关于删除非不同行的主要内容,如果未能解决你的问题,请参考以下文章