总结各种办法帮你搞定数据库里那些烦人的重复行删除问题
- 问答
- 2025-12-30 18:51:54
- 4
要删除数据库里的重复行,这事儿说麻烦也麻烦,说简单也简单,关键看你用对方法没有,网上的高手们,比如博客园的“追梦人物”、CSDN的众多技术博主以及Stack Overflow上的全球开发者,都分享过很多实用的技巧,下面我就把这些方法给你捋一捋,保证不用那些让人头疼的专业术语,用大白话讲明白。
第一步:千万别急着删!先备份!
这是所有老司机都会强调的铁律,在你动手执行任何删除操作之前,必须、一定、务必将你的数据表整个备份一下,SQL里有个很简单命令,CREATE TABLE 表名_backup AS SELECT * FROM 表名;,这样你就创建了一个名字叫“表名_backup”的备份表,万一删错了,你还能从这个备份表里把数据捞回来,这一步没做,后面的一切都免谈。
第二步:搞清楚什么样的算“重复”
“重复”这个词听起来简单,但在数据库里得有明确的定义,到底哪几列的内容完全一样才算重复行?比如你有一个用户表,是“姓名”一样就算重复,还是“姓名+手机号”一样才算重复?这个标准得由你根据业务来定,我们把这个标准里的列叫做“重复判断列”。
用ROW_NUMBER()函数给行排队,然后删掉多余的
这是目前最流行、最灵活的方法,适用于大多数数据库(比如MySQL 8.0以上、PostgreSQL、SQL Server等),它的思路特别直观:你不是觉得某些列重复吗?那我就先根据这些列把数据分组,然后在每个组里面,给每一行编个号(1,2,3...),最后只留下每组里编号为1的那一行,其他的都删掉。
具体操作分三步走:
- 先查看重复情况:你可以写个查询,看看按照你的标准,哪些行被标记为了重复项,语句大概是:
SELECT *, ROW_NUMBER() OVER (PARTITION BY 列1, 列2 ORDER BY 某个排序依据) as row_num FROM 表名;,这里,PARTITION BY后面跟的就是你定的“重复判断列”,ORDER BY是决定在同一组里谁排第1、谁排第2的依据(比如按时间最新的排第一)。 - 确认无误后,动手删除:上面的查询只是看看,现在来真的,语句会复杂一点,需要用一个子查询(可以理解为一个临时的查询结果):
DELETE FROM 表名 WHERE 主键ID IN ( SELECT 主键ID FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY 列1, 列2 ORDER BY 某个排序依据) as row_num FROM 表名 ) AS t WHERE t.row_num > 1 );,这个语句的意思就是,找出那些编号大于1的行(也就是重复的行),然后根据它们的主键ID(每行唯一的标识)进行删除。
这个方法的好处是控制力强,你可以通过ORDER BY子句精确决定保留哪一条(比如保留最近创建的记录)。
用GROUP BY找到重复组,保留一个最小值/最大值

这个方法更老派一些,思路是:先通过GROUP BY和“重复判断列”分组,然后找出每组里某个唯一标识(比如ID)最小或最大的那条记录保留,删除其他所有ID不满足条件的行。
操作如下:
DELETE FROM 表名 WHERE 主键ID NOT IN ( SELECT MIN(主键ID) FROM 表名 GROUP BY 列1, 列2 );
这个语句的意思是:先通过GROUP BY分组,然后找出每组里主键ID最小的那个值,删除那些主键ID不在这个“最小ID列表”里的所有行,这样,每个组就只留下了ID最小的那一行,你也可以把MIN换成MAX,保留ID最大的那条。
这个方法简单粗暴,但缺点是你只能根据ID的大小来决定保留谁,不如ROW_NUMBER()方法那样可以按任意字段(如创建时间)排序灵活。
超级简单的“去重创建新表”法
如果你的表数据量特别大,或者你求稳怕在原表上删除出问题,这是个好办法,思路就是:我直接创建一个全新的表,这个表的结构和旧表一模一样,但里面的数据已经是去重后的了。

步骤:
CREATE TABLE 新表名 AS SELECT DISTINCT 列1, 列2, 列3 ... FROM 旧表名;,这里的DISTINCT关键字会自动帮你过滤掉完全重复的行,但要注意,DISTINCT是针对你选择的所有列进行去重,所以你要把需要的列都写上。- 或者,你也可以用
GROUP BY来实现同样的效果:CREATE TABLE 新表名 AS SELECT * FROM 旧表名 GROUP BY 列1, 列2, ...;(这种写法在某些数据库里可能不适用,但MySQL中常用)。 - 新表创建好后,确认一下数据是否正确,如果正确,就可以把旧表删掉(或者重命名备份),再把新表的名字改成旧表的名字。
这个方法非常安全,因为完全不影响原始数据,缺点是如果表有自增主键之类的约束,新表需要重新设置,而且如果表很大,创建新表可能需要点时间。
对于有唯一主键的表的特殊情况
你的表本身就有唯一的主键,但其他业务列重复了,这时候,你可以利用一种“自连接”的技巧,简单说就是让表自己和自己比较。
语句类似:DELETE t1 FROM 表名 t1, 表名 t2 WHERE t1.id > t2.id AND t1.重复列 = t2.重复列;
这个语句的意思是:找出所有重复列相同,但ID比对方大的行(t1),然后删除这些ID大的行(t1),这样最终留下的就是每组重复项里ID最小的那条,这个方法本质上和方法二很像。
- 最推荐:方法一(ROW_NUMBER),功能最强,最灵活。
- 最稳妥:方法三(创建新表),适合大数据量或新手,安全第一。
- 最简洁:方法二(GROUP BY),如果需求简单,只是按ID保留一条,这个很直接。
最后再啰嗦一句,回到第一步,操作前务必备份!希望这些方法能帮你搞定那些烦人的重复行。
本文由凤伟才于2025-12-30发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/71430.html
