要查重复次数最多的单条记录,需用GROUP BY配合ORDER BY COUNT(*) DESC LIMIT 1;仅用HAVING无法直接实现,因HAVING不能跨组比较聚合值。

直接查出重复次数最多的单条记录
用 GROUP BY 配合 HAVING 只能筛出“所有重复组”,不能直接返回“重复最多”的那一个。真要只拿一条,得靠 ORDER BY COUNT(*) DESC LIMIT 1。
比如查 user 表中出现次数最多的 username:
SELECT username, COUNT(*) AS cnt FROM user GROUP BY username ORDER BY cnt DESC LIMIT 1;
注意点:
-
GROUP BY必须包含所有非聚合字段,否则 MySQL 8.0+ 会报错(ONLY_FULL_GROUP_BY模式默认开启) - 如果
username允许为NULL,它会被单独分组;需要排除就加WHERE username IS NOT NULL - 多个用户名并列第一时,
LIMIT 1只随机返回一个,不保证稳定性
查出所有并列“重复最多”的记录
当有多个值重复次数相同且都是最高时,上面的 LIMIT 1 会漏掉其余项。得先算出最大重复数,再匹配:
SELECT username, cnt
FROM (
SELECT username, COUNT(*) AS cnt
FROM user
WHERE username IS NOT NULL
GROUP BY username
) AS t
WHERE cnt = (
SELECT MAX(cnt)
FROM (
SELECT COUNT(*) AS cnt
FROM user
WHERE username IS NOT NULL
GROUP BY username
) AS tmp
);这个写法虽稍长,但结果确定、可复现。常见坑:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 子查询里漏掉
WHERE username IS NOT NULL,会导致MAX(cnt)被NULL分组干扰 - 嵌套太深时,MySQL 可能无法用上索引,建议在
username上建普通索引:CREATE INDEX idx_username ON user(username);
多字段组合重复时怎么找“最多”
比如要统计 (username, phone) 组合中哪一组出现最多:
SELECT username, phone, COUNT(*) AS cnt FROM user WHERE username IS NOT NULL AND phone IS NOT NULL GROUP BY username, phone ORDER BY cnt DESC LIMIT 1;
关键区别:
-
GROUP BY必须写全字段:GROUP BY username, phone,不能只写一个 - 联合判断时,
NULL在任一字段出现都会导致该行被排除(因为NULL = NULL不成立),所以WHERE条件要分别判空 - 若想加速,需建联合索引:
CREATE INDEX idx_user_phone ON user(username, phone);,顺序不能颠倒(按GROUP BY字段顺序来)
为什么不能只用 HAVING 就搞定“最多”
HAVING 是过滤分组后的结果,但它没有“比较组间大小”的能力。例如下面这句语法合法但逻辑错误:
SELECT username, COUNT(*) FROM user GROUP BY username HAVING COUNT(*) = MAX(COUNT(*)); -- ❌ 错误:MAX() 不能嵌套聚合函数这样用
MySQL 不允许在 HAVING 中对聚合结果再做聚合运算。必须拆成两步:先聚合出各组数量,再在外层比大小。这也是最容易卡住的地方——很多人写完 HAVING COUNT(*) > 1 就以为能顺延出“最多”,其实跨不过去。
真正要压测或跑在大表上时,别只盯着 SQL 写法,先确认 GROUP BY 字段有没有索引,以及数据倾斜程度。万一某个 username 占了 80% 的行,COUNT(*) 本身就会变慢,这时候就得考虑加 WHERE 限流或改用物化视图预计算。

















