SQL删除重复记录只留一条_利用ROW_NUMBER窗口函数处理

1次阅读

必须用子查询或 CTE 先标出行号再删除,因 SQL Server、PostgreSQL、MySQL 8.0+ 均不支持窗口函数直接出现在 DELETE 的 WHERE 子句中;正确做法是通过 PARTITION BY 定义重复逻辑,ORDER BY 指定保留规则,并确保相关字段有联合索引以提升性能。

SQL 删除重复记录只留一条_利用 ROW_NUMBER 窗口函数处理

ROW_NUMBER() 删重复数据前必须加 WHERE 子查询

直接在 DELETE 里写 ROW_NUMBER() 会报错——SQL Server、PostgreSQL、MySQL 8.0+ 都不支持窗口函数出现在 DELETEWHERE 子句里。你得先用子查询把要删的行标出来,再套一层 DELETE

常见错误现象:Window function is not allowed in WHERE clauseInvalid use of window function

  • 正确做法是:用 WITH 或子查询生成带 rn(行号)的结果集,再对 rn > 1 的行执行删除
  • 别漏掉 PARTITION BY 字段——它定义“哪些算重复”,比如按 emailname 重复,就写 PARTITION BY email, name
  • ORDER BY 决定哪条被保留:想留最新的一条,就按 created_at DESC;想留最早的一条,就用 ASC

MySQL 8.0+ 删除重复记录的最小可行写法

MySQL 支持 CTE,但不能直接在 DELETE 中引用 CTE 别名(会报 ERROR 1093)。得用两层包装。

WITH ranked AS (SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at DESC) AS rn   FROM users ) DELETE FROM users WHERE id IN (SELECT id FROM ranked WHERE rn > 1);
  • 注意:外层 DELETEFROM users 必须和 CTE 中的表名一致,否则 MySQL 可能拒绝执行
  • 如果表有主键且你想保留最小 id 的那条,把 ORDER BY 换成 id ASC
  • 没主键?用 ORDER BY (SELECT NULL) 是允许的,但保留哪条完全随机,慎用

SQL Server 用 CTE + DELETE 更简洁

SQL Server 允许直接从 CTE 删除,只要 CTE 引用的是单个基表。

WITH dupes AS (SELECT *,          ROW_NUMBER() OVER (PARTITION BY email ORDER BY updated_at DESC) AS rn   FROM users ) DELETE FROM dupes WHERE rn > 1;
  • 这个写法比 MySQL 少一层嵌套,但前提是 CTE 不能含 JOIN、聚合或子查询,否则报错 View or function 'dupes' is not updatable
  • 如果表有触发器,DELETE FROM CTE 仍会触发,行为和普通 DELETE 一致
  • 执行前建议先 SELECT * FROM dupes WHERE rn > 1 确认要删的内容

性能与索引:PARTITION BY 字段没索引会很慢

ROW_NUMBER() 在大表上执行时,数据库需要排序并分组。如果 PARTITION BY 字段没索引,可能全表扫描 + 外部排序,几百万行就卡住。

  • PARTITION BY 列建联合索引最有效,例如:CREATE INDEX idx_email_updated ON users(email, updated_at DESC);
  • PostgreSQL 对 ORDER BY …… DESC 索引支持好;MySQL 8.0+ 也支持降序索引,但老版本会忽略 DESC 关键字
  • 别在生产环境跑前不加 LIMIT 测试——先用 SELECT COUNT(*) 看重复量级,再决定是否分批删

真正麻烦的不是语法,是删完发现业务逻辑依赖了被删掉的“重复但不同”的记录,比如用不同 source 字段标识导入渠道,结果只按 email 去重把有效数据干掉了。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-19发表,共计1546字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources