查重复需先明确定义“重复”字段组合;用GROUP BY+HAVING COUNT()>1最稳妥,不可在WHERE中使用COUNT();单字段重复需注意NULL归组和大小写敏感问题;多字段联合重复须将所有判重字段列入GROUP BY;查完全重复行要排除自增ID且覆盖所有非主键字段;想获取全部重复记录需用子查询、自连接或窗口函数;常见查不到原因包括漏HAVING、误用WHERE、索引未生效及字段隐式转换。

直接查重复,先明确“重复”指哪几个字段组合相同;用 GROUP BY + HAVING COUNT(*) > 1 是最稳的起点,别碰 WHERE COUNT(*) > 1 —— 那会报错。
查单字段重复(如 email)
只看一个字段是否重复,比如用户邮箱是否被多人注册:
-
SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1—— 返回重复值及其出现次数 - 注意:如果
email允许为NULL,MySQL 默认把所有NULL归为一组,可能误判为“重复”。真要排除NULL,得加WHERE email IS NOT NULL - 大小写敏感?默认是。若业务认为
Zhang@x.com和zhang@x.com相同,得写GROUP BY LOWER(email),但会失效索引,大表慎用
查多字段联合重复(如 order_no + user_id)
订单号和用户 ID 同时一样才算重复,这是常见业务逻辑:
SELECT order_no, user_id, COUNT(*) FROM orders GROUP BY order_no, user_id HAVING COUNT(*) > 1- 必须把所有判重字段都列进
GROUP BY,漏一个就可能漏掉真实重复 - 字段含
NULL时同样归组,但后续做JOIN或IN匹配时,NULL = NULL不成立,容易漏数据。稳妥做法是提前用COALESCE(col, '')统一空值
查完全重复行(所有字段值都一样)
整行数据一字不差才算重复,比如导入时没去重导致的全量复制:
-
SELECT a, b, c, COUNT(*) FROM t GROUP BY a, b, c HAVING COUNT(*) > 1—— 前提是a,b,c覆盖表中所有非主键字段 - 千万别把自增
id放进GROUP BY,否则每组只有 1 行,永远查不到重复 - 想看到所有重复的原始记录(不只是统计),不能只靠上面那句。得用子查询或自连接,例如:
SELECT t1.* FROM t t1 INNER JOIN (SELECT a, b, c FROM t GROUP BY a, b, c HAVING COUNT(*) > 1) t2 ON t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c - MySQL 8.0+ 更推荐窗口函数:
SELECT *, COUNT(*) OVER (PARTITION BY a, b, c) AS dup_cnt FROM t,直接在结果里标出每行属于第几条重复
为什么查不到重复?常见卡点
不是语法错,而是逻辑或环境问题:
- 执行了
GROUP BY却没加HAVING,结果只是分组展示,看不出哪些组超 1 行 - 用了
WHERE COUNT(*) > 1—— 这是非法语法,COUNT()是聚合函数,只能在HAVING里用 - 表有唯一索引但还没建,或者建了但没生效(比如 ALTER TABLE 没提交、或用了 MyISAM 引擎不支持事务级约束)
- 字段类型隐式转换干扰判断,比如
VARCHAR字段末尾有空格,'abc '和'abc'在某些排序规则下不等,但GROUP BY可能又认为相等——建议统一用TRIM()处理再分组
真正难的不是写出第一句 GROUP BY,而是确认“业务上什么叫重复”——这个定义一旦偏差,后面所有操作都是在清理错误目标。


















