SQL去重的三种方法汇总

说白了,SQL去重其实很简单,关键看你想达到什么效果。
先说最重要的,如果你只是想计算去重后的数量,那DISTINCT绝对是你的首选。
去年我们跑的那个项目,我们就是用COUNT(DISTINCT)来计算不同任务的数量,大概3 000量级,简单又高效。

另外一点,如果你需要对多字段进行去重,GROUPBY也是个不错的选择。
不过,得配合聚合函数一起用。
我一开始以为GROUPBY只能按一个字段分组,后来发现不对,其实可以按多个字段分组,这样就能实现类似DISTINCT的效果。
等等,还有个事,如果你用GROUPBY,在MySQL中,非分组字段可能会返回组内任意值,这个点很多人没注意。

还有个细节挺关键的,那就是ROW_NUMBER()窗口函数。
这个在处理复杂去重逻辑时特别有用,比如你想保留每组中最早开始时间的记录。
不过,这个函数不是所有数据库都支持,像Hive、Oracle这类数据库才有。

最后提醒一下,性能方面,DISTINCT在大数据量时效率较低,而GROUPBY或窗口函数可能更优。
如果你在做多字段去重,用DISTINCT和GROUPBY都可以,但GROUPBY的灵活性更高。
这个点很多人没注意,我觉得值得试试。

如何使用 DISTINCT 关键字在 MySQL 中按条件去重字段?

哎哟,这MySQL里的DISTINCT关键字,真是让人又爱又恨。
当年2 02 2 年那会儿,我在某个城市,接了个项目,得处理个大数据量的去重问题,那时候我真是懵了,不知道从何下手。
后来啊,我慢慢反应过来,得结合具体需求来设计查询逻辑。

第一个场景,直接使用DISTINCT多字段组合,这可是简单粗暴,直接在domain和isout字段上用。
当时我就是这样写的:SELECT DISTINCT domain, isout FROM url;原理啊,就是DISTINCT作用于所有选定字段的组合,确保结果中(domain,isout)唯一。
这适用场景嘛,就是需要同时显示区分条件字段,比如isout,这时候就用得上。

第二个场景,没明确区分字段,那得玩点花活。
我记得那时候,我需要按domain去重,但只保留“境外”或“境内”的记录,我用了两个方法。
第一个方法是UNION ALL合并结果,这玩意儿我用了两条SQL语句,一条获取所有境外domain(去重),另一条获取所有境内domain(去重),然后它们一合并,我就得到了我想要的结果。
不过,得注意啊,如果某个domain同时存在“境内”和“境外”记录,这查询会保留两条记录。

第二个方法,我优先保留特定条件记录,比如优先保留“境外”。
这我用了子查询,优先选择loc='境外'的记录,仅当不存在境外记录时才选择境内记录。

第三个场景,我用的是MySQL8 .0+的窗口函数ROW_NUMBER(),这玩意儿灵活得很,可以按时间排序取最新记录。
我当时是这样写的:WITH ranked_urls AS (SELECT domain, loc, ROW_NUMBER() OVER (PARTITION BY domain ORDER BY CASE WHEN loc='境外' THEN 1 ELSE 2 END, create_time DESC) AS rn FROM url) SELECT domain, loc FROM ranked_urls WHERE rn=1 ;这优势啊,就是可以自定义优先级,比如境外优先、时间倒序。

关键注意事项嘛,我总结了一下:性能优化,对domain和条件字段(如loc)建立索引,避免全表扫描;需求明确,确认是否需要保留区分字段或仅需去重后的domain列表;数据一致性,若存在跨条件重复,需通过业务逻辑明确处理规则。
这玩意儿,根据实际表结构和业务规则选择最适合的方案,我就这么干的。
哎,说起来都是泪啊,那时候真是头秃。

mysql 删除重复的数据

哎,我最近在做数据库清洗的时候,就踩了这个坑。
那时候,我们公司的一个项目数据库里,有一大堆重复的数据。
我一开始想用DISTINCT关键字来处理,结果发现,这货只能处理完全相同的行,对于那些只部分列不同的,根本就不管用。

记得是2 02 0年那会儿,我们那个项目表里有几百万条数据,其中有一列是用户ID,结果发现很多用户ID是重复的,但是其他列数据却不一样。
当时我就想,得,DISTINCT关键字不靠谱,得另想办法。

然后我就开始捣鼓GROUP BY,这个玩意儿倒是能按列组合去重,但是要用聚合函数,还得统计数据分布,感觉有点复杂。
那时候我手头也没那么多时间,就想着先简单处理一下,结果还是有点麻烦。

后来我又想,干脆用HAVING来过滤一下,把那些只出现一次的重复数据删掉。
结果,我发现这个HAVING只能过滤分组后的数据,对于原始数据还是没辙。

最后,我实在没办法了,只能试试子查询结合DELETE语句。
这个方法倒是挺管用的,我写了一个子查询,找出了重复的记录,然后直接DELETE掉。
不过,这玩意儿删除操作是不可逆的,我就赶紧先备份了一下数据,再进行操作。

这事儿让我深刻体会到,做数据库处理的时候,一定要先测试,别直接上DELETE操作,一不小心就把数据删没了。
以后遇到这种问题,我肯定会先通过SELECT验证结果,然后再执行DELETE操作,避免再踩坑了。
哎,说起来都是泪啊。