我有一个具有唯一非聚集索引的表,并且此索引中列出了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
内部联接内部的选择返回我们想要删除的正确数量的记录,但是将它们分组以便实际上有两倍的数量。
加入后会显示所有记录,但我想要删除的是最早的记录吗?
如何做到这一点?
答案 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(行标识符)。
所以:
请注意,在大表上重新创建索引可能需要很长时间。