sql 查询去除重复最常用两种核心方式,第一种是 distinct 关键字,针对整行数据做全局去重,第二种是 group by 分组去重,适合按指定字段分组,还可以搭配聚合函数做统计,两种方式适用场景不一样,很多新手容易混淆,distinct 只能简单去掉完全一模一样的整行记录,如果只想按某一个字段去重,同时还要保留其他字段数据,单纯 distinct 就不够用,这时候就要用到 row_number 窗口函数,这种方案在 sqlite3 mysql 高版本数据库里面都可以使用,去重本质就是把重复记录筛选,保留我们需要的那一条,其余重复行过滤掉,写 sql 的时候一定要明确需求,是整行全部字段重复才删除,还是只按照单个或者多个字段判断重复,需求不同写法差别很大,如果需求判断错误,会出现数据误删或者去重不彻底的问题。
三种去重方案对比表格
| 方案 | 核心原理 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| distinct | 查询结果整行完全相同就只保留一条 | 简单整行去重,不需要聚合统计 | 语法简单,一行代码实现 | 只能整行去重,不能按单字段去重保留其他列,无法搭配复杂统计 |
| group by | 按字段分组,每组只输出一条 | 按字段分组,同时需要 count sum 这类聚合计算 | 可以做统计,支持多字段分组 | 如果 select 后面写非分组字段,部分数据库会报错 |
| row_number 窗口函数 | 给重复分组内记录编号,只取编号为 1 的记录 | 按指定字段判断重复,保留最新或者最早一条 | 灵活,可以自定义保留哪一条重复数据 | 语法相对复杂,低版本数据库不支持窗口函数 |
实操使用步骤
第一步 确认去重需求,先判断是不是整行所有字段都完全重复,如果是,直接使用 distinct,语法示例 select distinct id name age from user。
第二步 如果需要按照某个字段分组,同时做统计,选择 group by,语法示例 select name count from user group by name,按照 name 分组统计每组数量。
第三步 如果是只按某字段判断重复,还要保留其他列,选择 row_number 窗口函数,示例 select from select row_number over partition by name order by id as rn from user t where rn = 1,partition by 后面填写判断重复的字段,order by 决定保留哪一条,比如按 id 升序就是保留最早一条,降序就是保留最新一条。
第四步 执行查询验证结果,运行 sql 之后检查输出记录,确认重复数据已经被过滤,没有多余重复行。
第五步 如果是需要永久删除表里的重复数据,而不是查询的时候临时去重,需要结合上面查询逻辑,把重复多余记录 delete 删除,注意操作前一定要备份数据表,防止误删原始数据。
补充注意要点
1 distinct 写在 select 后面,紧跟 select 关键字,不能写在 where 后面
2 group by 分组字段,必须和 select 里面非聚合字段保持一致,mysql 开启严格模式的时候不遵守这个规则会直接报错
3 多字段判断重复的时候,partition by 后面可以写多个字段,逗号隔开,代表多个字段组合起来判定为重复
4 sqlite3 同样支持这三种去重写法,sqlite3 3.25 版本之后才支持 row_number 窗口函数,老版本 sqlite3 只能用 distinct 或者 group by 实现基础去重
综合来看,简单整行去重用 distinct,分组统计用 group by,按字段去重并保留其他列优先选 row_number 窗口函数,写 sql 查询去除重复之前,一定要先明确判定重复的字段和保留规则,避免逻辑出错。
【常见问题】
问题 1 sql 查询去除重复可以只根据一个字段去重吗
回答 1 sql 查询去除重复单纯 distinct 做不到只按单字段去重保留其他列,想要单字段判定重复,需要使用 row_number 窗口函数,partition by 指定这个字段实现查询去除重复。
问题 2 sql 查询去除重复 distinct 和 group by 哪个性能更好
回答 1 简单场景下两者性能差距不大,如果只是单纯查询去除重复,distinct 可读性更好,如果需要同时聚合统计,group by 更合适,大表场景下 group by 优化空间更高。
问题 3 sqlite3 里面 sql 查询去除重复支持 row_number 吗
回答 1 sqlite3 版本大于等于 3.25 才支持 row_number 窗口函数,低版本 sqlite3 做 sql 查询去除重复只能使用 distinct 或者 group by 两种基础方案。
【免责申明】
本内容基于标准 SQL 语法以及 sqlite3 mysql 数据库公开文档整理,不同数据库版本语法兼容存在差异,内容仅供学习参考,正式业务执行删除类操作前请做好数据备份,不保证所有特殊表结构场景都完全适用。


