mysql中删除重复数据的SQL语句写法

来源:这里教程网 时间:2026-02-28 20:49:10 作者:

GROUP BY
+
MIN(id)
找出要保留的记录

MySQL 没有直接的“去重删除”语法,得先明确保留哪一条:通常选

id
最小(或最大)的那条。假设表叫
users
,重复依据是
email
字段,那么先查出每个
email
对应的最小
id

SELECT MIN(id) AS keep_id, email
FROM users
GROUP BY email;

这个结果就是你“想留下的那些行”。下一步就是删掉其余的。

DELETE ... JOIN
一次性删掉重复行

这是最常用、效率也相对可控的方式。核心思路:把原表和刚才的分组结果做

LEFT JOIN
,找出没被匹配上的那些行(即该
email
id
不是最小的),然后删掉它们:

DELETE u1 FROM users u1
LEFT JOIN (
    SELECT MIN(id) AS keep_id, email
    FROM users
    GROUP BY email
) u2 ON u1.email = u2.email AND u1.id = u2.keep_id
WHERE u2.keep_id IS NULL;
u1
是原表别名,
u2
是子查询结果别名
ON
条件里必须同时匹配
email
id
,否则会误删
WHERE u2.keep_id IS NULL
表示这条
u1
记录没找到对应的“保留 ID”,该删

注意主键和索引对执行的影响

如果

email
字段没建索引,
GROUP BY
JOIN
都会变慢,大表可能卡住甚至超时:

执行前加索引:
CREATE INDEX idx_email ON users(email);
若表有自增
id
主键,上面语句能用;但若没有主键或用复合唯一键,得改用
ROW_NUMBER()
(仅 MySQL 8.0+ 支持)
MySQL 5.7 及更早版本不支持窗口函数,别写
ROW_NUMBER() OVER (PARTITION BY email ORDER BY id)
,会报错
ERROR 1064

误删风险高,务必先备份或用事务测试

这条

DELETE
语句不可逆。线上操作前必须:

在测试库跑一遍,确认影响行数:
SELECT COUNT(*) FROM users u1 LEFT JOIN (...) u2 ... WHERE u2.keep_id IS NULL;
用事务包住,删完立刻
SELECT
验证:
START TRANSACTION;
DELETE u1 FROM users u1 ... ;
SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;
如果表很大,考虑分批删(比如按
id
范围),避免锁表太久

真正难的不是写出语句,而是确认“哪些字段才算重复”“保留逻辑是否符合业务”,比如两个

email
相同但
status
不同,该留激活的还是未激活的——这得看需求,SQL 本身不会替你判断。

相关推荐