MySQL 8.0中如何使用ROW_NUMBER函数高效删除重复记录?

酷芳大大_7966

酷芳大大_7966

2026-09-04

857人浏览

原创

mysql中delete不能直接使用row_number(),因窗口函数禁用于where子句且禁止同一语句中读写同表;必须用cte或子查询包装后join删除,order by决定保留行,操作前需验证、备份并确保索引与版本支持。

mysql 8.0中如何使用row_number函数高效删除重复记录?

必须用子查询或CTE包装ROW_NUMBER()结果,再关联删除;直接在DELETE中写窗口函数会报错,且ORDER BY方向决定哪条数据被保留。

为什么DELETE里不能直接用ROW_NUMBER()

MySQL不允许在DELETE语句的WHERE子句中直接调用窗口函数,会报错Window function is not allowed in WHERE clause。更关键的是,即使绕过语法检查,也无法在同一个语句中对同一张表既查又删——执行DELETE FROM t WHERE id IN (SELECT id FROM t ... ROW_NUMBER() ...)会触发Error 1093: You can't specify target table 't' for update in FROM clause。

解决路径只有一条:把带ROW_NUMBER()的结果当临时结果集(派生表或CTE),再让外层DELETE通过JOIN或IN引用它。

  • CTE写法更清晰,但仅MySQL 8.0.1+支持,且需注意语法:MySQL不支持DELETE FROM tbl USING cte那种PostgreSQL风格,得用DELETE t1 FROM t1 JOIN cte ON ...
  • 子查询写法兼容性更好,但嵌套两层是硬性要求:内层算rn,中层筛选rn > 1,外层执行删除
  • 别信“加了GROUP BY就能删”的简化写法,那只是去重逻辑错觉,实际无法保证字段完整性

ORDER BY怎么写才真正控制“留哪一条”

ORDER BY不是为了好看,它直接决定ROW_NUMBER() = 1落在哪一行。比如PARTITION BY email ORDER BY created_at DESC会让最新时间的记录排第一,从而被保留;反过来写ASC就留下最老的一条。

常见踩坑点:

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • 用id排序时,默认ASC会留最小ID,但若业务要留最新插入的,而ID又不是自增主键(比如UUID或业务生成ID),结果就不可控
  • 字段含NULL时,MySQL 8.0.22+才支持ORDER BY col DESC NULLS LAST,旧版默认把NULL排最前,可能误删本该保留的记录
  • 多条件优先级不能靠多个ORDER BY字段堆砌,得用CASE表达式量化权重,例如优先保留status = 'active',再按时间降序: ORDER BY CASE WHEN status = 'active' THEN 0 ELSE 1 END, created_at DESC

删除前必须验证和备份的实操动作

执行DELETE前不验证等于闭眼开车。先跑一遍等价的SELECT语句,确认哪些ID会被删:

SELECT id, email, created_at, 
       ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at DESC) AS rn 
FROM users 
WHERE rn > 1;

但注意:上面这句会报错,因为WHERE rn > 1不能直接用别名。正确预览写法是:

SELECT * FROM (
  SELECT id, email, created_at, 
         ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at DESC) AS rn 
  FROM users
) t WHERE rn > 1;
  • 务必先执行CREATE TABLE users_backup AS SELECT * FROM users;,尤其当表无主键或PARTITION BY字段有大量NULL时,误删风险极高
  • 大表操作建议套事务:BEGIN; DELETE ... ; SELECT ROW_COUNT(); ROLLBACK;,确认行数合理再COMMIT
  • 如果PARTITION BY字段没索引,ROW_NUMBER()计算会全表扫描,100万行以上可能卡住,删之前先加复合索引,如ALTER TABLE users ADD INDEX idx_email_time (email, created_at);

低版本MySQL(如5.7)根本不能用ROW_NUMBER()

执行SELECT VERSION();确认版本号≥8.0.2,否则会报错FUNCTION yourdb.ROW_NUMBER does not exist。5.7及更早版本只能换方案:

  • 用自连接:DELETE t1 FROM users t1 INNER JOIN users t2 ON t1.email = t2.email AND t1.id > t2.id;——小表可用,大数据量易锁表、慢
  • 用临时表导出再导入,适合一次性清理且能停服的场景
  • 用应用层分批拉取+去重+回写,适合需要复杂业务判断的场景

窗口函数不是银弹,它只解决“按明确规则留一条”的问题;如果重复行之间差异极小、或保留逻辑依赖外部状态(比如要查另一张表判断是否激活),就得跳出SQL,用程序逻辑兜底。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

3983

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

851

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1029

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5841

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2763

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5820

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7741

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1050

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

932

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 178人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 283人学习