首先,我怀疑结果不准确?原始表格中好像有三个'Sam'。但这对问题本身并不重要。
然后,我们来谈谈问题本身。基于您的表格,显示重复值的最佳方法是使用
count(*)
和
Group by
子句。查询将如下所示:
SELECT OrderNo, shoppername, amountPayed, city, item, count(*) as RepeatTimes FROM dbo.sales GROUP BY OrderNo, shoppername, amountPayed, city, item HAVING COUNT(*) > 1
原因是从您的表格中所有列一起唯一标识每条记录,这意味着仅当每列的所有值完全相同时,记录才会被视为重复,并且您要显示重复记录的所有字段,因此
group by
将不会错过任何列,否则是因为您只能在“group by”子句中选择参与的列。
现在我想给您一个关于
With...Row_Number()Over(...)
的例子,它使用表达式和Row_Number函数。
假设你有一个几乎相同的表格,但多了一列名为Shipping Date的列,而其值可能不同于其他行。如下所示:
OrderNo shoppername amountpayed city Item Shipping Date
1 Sam 10 A Iphone 2016-01-01
1 Sam 10 A Iphone 2016-02-02
1 Sam 5 A Ipod 2016-03-03
2 John 20 B Macbook 2016-04-04
3 John 25 B Macbookair 2016-05-05
4 Jack 5 A Ipod 2016-06-06
请注意,如果您仍将所有列视为一个单位,则第2行不是重复行。但如果您在此情况下也要将它们视为重复行怎么办?您应该使用With...Row_Number()Over(...)
,查询将如下所示:
WITH TABLEEXPRESSION
AS
(SELECT *,ROW_NUMBER() OVER (PARTITION BY OrderNo, shoppername, amountPayed, city, item ORDER BY [Shipping Date] as Identifier) --如果您认为运送日期较晚的是重复项
FROM dbo.sales)
SELECT * FROM TABLEEXPRESSION
WHERE Identifier !=1 --或使用 '>1'
以上查询将返回包括Shipping Date在内的结果,例如:
OrderNo shoppername amountpayed city Item Shipping Date Identifier
1 Sam 10 A Iphone 2016-02-02 2
请注意,此结果与2016-01-01不同,2016-02-02被过滤的原因是 PARTITION BY OrderNo, shoppername, amountPayed, city, item ORDER BY [Shipping Date] as Identifier
,而Shipping Date并不是需要处理重复记录的列之一,这意味着2016-02-02仍然可能是您问题的完美答案。
现在简要总结一下,使用count(*)
和Group by
子句一起是最好的选择,当您只想显示所有来自Group by
子句的列作为结果时,否则您将错过那些不参与group by
的列。
而对于With...Row_Number()Over(...)
,它适用于您想要查找重复记录的每种情况,但是与前者相比,编写查询有点复杂且有点过度设计。
如果您的目的是从表中删除重复记录,则必须使用后面的WITH...ROW_NUMBER()OVER(...)...DELETE FROM...WHERE
。
希望这可以帮助您!
with x as (select t.*, row_number() over(PARTITION BY OrderNo, item order by OrderNo) as rn from t_dcf t) select * from x where rn > 1;
- Juan