HAVING可独立于GROUP BY使用,此时全表视为一组;其核心用途是过滤分组结果,条件中只能用常数、聚合函数和聚合键,且必须位于GROUP BY之后。

用 GROUP BY + HAVING 查重复字段值
这是最直接、兼容性最好的方式,适用于所有支持标准 SQL 的数据库(MySQL、PostgreSQL、openGauss 等)。核心思路是:按目标字段分组,再筛选出计数大于 1 的组。
假设你要查 users 表中 email 字段的重复值:
SELECT email, COUNT(*) AS cnt FROM users GROUP BY email HAVING COUNT(*) > 1;
注意点:
-
HAVING必须写在GROUP BY之后,不能用WHERE替代——因为COUNT(*)是聚合结果,WHERE在分组前执行,无法过滤聚合值 - 如果想同时看到重复行的完整记录(比如 ID、姓名),得用子查询或
IN关联原表,单纯靠这个语句只能看到重复值和出现次数 - DBeaver 执行后,默认会把结果放在「结果」标签页,可直接排序、导出,不用额外配置
查重复时要显示所有重复行(含 ID、时间等)
上面的 GROUP BY 只返回去重后的值和次数,但排查问题常需要原始数据。这时推荐用窗口函数 COUNT() OVER(MySQL 8.0+、PostgreSQL、openGauss 支持):
SELECT id, email, created_at,
COUNT(*) OVER (PARTITION BY email) AS dup_cnt
FROM users
WHERE COUNT(*) OVER (PARTITION BY email) > 1;
但注意:MySQL 8.0+ 不允许在 WHERE 中直接使用窗口函数,得套一层子查询:
SELECT id, email, created_at, dup_cnt
FROM (
SELECT id, email, created_at,
COUNT(*) OVER (PARTITION BY email) AS dup_cnt
FROM users
) t
WHERE dup_cnt > 1;
常见坑:
- 旧版 MySQL(5.7 及更早)不支持窗口函数,强行运行会报错
ERROR 1064,此时只能退回用自连接或关联子查询 -
PARTITION BY后的字段要注意 NULL 值处理——默认情况下,多个NULL会被视为同一组,如果你业务中email IS NULL是合法值且不应参与去重判断,得加WHERE email IS NOT NULL
DBeaver 自带的“查找重复”功能在哪
DBeaver 本身没有一键标出重复值的独立按钮,但可以通过「数据编辑器」的筛选+排序快速人工识别:
操作路径:右键表 → 编辑数据 → 点击列头(如 email)→ 升序/降序排列 → 相邻相同值一目了然。
配合以下技巧效率更高:
- 开启「自动滚动到匹配项」:在数据编辑器右上角齿轮图标 → 勾选
Auto scroll to matching rows,然后 Ctrl+F 输入某个邮箱,它会高亮并跳转所有匹配行 - 导出为 CSV 后用 Excel 的「条件格式 → 突出显示重复值」,适合小数据量快速肉眼确认
- 别依赖 DBeaver 的「过滤器」输入
email = 'xxx'来逐个验证——这没法批量发现未知重复值
大表查重复的性能提醒
对千万级 users 表直接跑 GROUP BY email,没索引的话可能卡住或超时。关键动作就一个:
先确认 email 字段是否有索引:
SHOW INDEX FROM users WHERE Column_name = 'email';
如果没有,且该字段经常用于查重或唯一约束,应尽快加索引:
ALTER TABLE users ADD UNIQUE INDEX idx_email (email);
注意:
-
UNIQUE索引能防止新插入重复值,但不会自动清理已有重复;已有重复必须先人工或脚本处理掉,否则建索引会失败并报错ERROR 1062 - 如果只是临时查重,用普通
INDEX(非唯一)也够用,比全表扫描快几个数量级 - DBeaver 的「执行计划」按钮(闪电图标)可以查看
EXPLAIN结果,确认是否命中索引——这点容易被忽略,但对线上大表至关重要











