我有一张非常大的行数表格。由于创建行时出现了问题,不能允许重复,但我知道在这个表格中有一些重复的行。
我需要从关键列的角度消除多余的行。其他某些列可能具有略微不同的数据,但我不关心。但是我仍然需要保留其中的一行。SELECT DISTINCT 将行不通,因为它操作所有列,而我需要根据关键列压制重复项。
如何高效地删除额外的行但仍保留其中一行?
我有一张非常大的行数表格。由于创建行时出现了问题,不能允许重复,但我知道在这个表格中有一些重复的行。
我需要从关键列的角度消除多余的行。其他某些列可能具有略微不同的数据,但我不关心。但是我仍然需要保留其中的一行。SELECT DISTINCT 将行不通,因为它操作所有列,而我需要根据关键列压制重复项。
如何高效地删除额外的行但仍保留其中一行?
你没有说你使用的是哪个版本,但在SQL 2005及以上版本中,你可以使用一个带OVER子句的公用表达式。大致如下:
WITH cte AS (
SELECT[foo], [bar],
row_number() OVER(PARTITION BY foo, bar ORDER BY baz) AS [rn]
FROM TABLE
)
DELETE cte WHERE [rn] > 1
尝试调整并查看结果。
(编辑:为了提供帮助,某人编辑了CTE中的ORDER BY
子句。需要明确的是,在此处可以按任何想要的方式进行排序,不一定是由cte返回的列之一。实际上,这里常见的用例是"foo,bar"是分组标识符,“baz”是某种时间戳。为了保持最新状态,您应该使用 ORDER BY baz desc
。)
示例查询:
DELETE FROM Table
WHERE ID NOT IN
(
SELECT MIN(ID)
FROM Table
GROUP BY Field1, Field2, Field3, ...
)
这里的fields
是您想要按其中重复的行分组的列。
下面是我的改进版本,附带可运行的示例。注意,这只适用于Id
唯一且其他列中存在重复值的情况。
DECLARE @SampleData AS TABLE (Id int, Duplicate varchar(20))
INSERT INTO @SampleData
SELECT 1, 'ABC' UNION ALL
SELECT 2, 'ABC' UNION ALL
SELECT 3, 'LMN' UNION ALL
SELECT 4, 'XYZ' UNION ALL
SELECT 5, 'XYZ'
DELETE FROM @SampleData WHERE Id IN (
SELECT Id FROM (
SELECT
Id
,ROW_NUMBER() OVER (PARTITION BY [Duplicate] ORDER BY Id) AS [ItemNumber]
-- Change the partition columns to include the ones that make the row distinct
FROM
@SampleData
) a WHERE ItemNumber > 1 -- Keep only the first unique item
)
SELECT * FROM @SampleData
结果如下:
Id Duplicate
----------- ---------
1 ABC
3 LMN
4 XYZ
不确定为什么我首先想到了那个...这绝对不是最简单的方法,但它可以工作。
ROW_NUMBER()
函数。 - Cᴏʀʏ