SQL如何快速找出重复记录并统计数量_GROUP BY加COUNT实现

2次阅读

最稳做法是 SELECT 字段, COUNT() FROM 表 GROUP BY 字段 HAVING COUNT()>1;聚合函数不可用于 WHERE,必须用 HAVING 筛选;多字段重复需在 GROUP BY 中包含所有字段;NULL 值会被归为一组,需 WHERE 排除空值再统计。

SQL 如何快速找出重复记录并统计数量_GROUP BY 加 COUNT 实现

怎么用 GROUP BY + COUNT 找出重复值

直接在 GROUP BY 字段后加 COUNT(*),再用 HAVING 筛出数量大于 1 的组。这是最稳、最通用的做法,所有主流 SQL 数据库都支持。

常见错误是把 COUNT(*) 放在 WHERE 里——不行,聚合函数不能进 WHERE,必须用 HAVING

  • SELECT name, COUNT(*) FROM users GROUP BY name HAVING COUNT(*) > 1
  • 想看完整记录?得用子查询或窗口函数,GROUP BY 本身只返回每组一条结果
  • 多个字段判重?比如“姓名 + 手机号”组合重复:GROUP BY name, phone,别漏掉任一字段

为什么不能只用 DISTINCT 或 EXISTS

DISTINCT 只去重,不告诉你哪条重复、重复几次;EXISTS 子查询写起来绕,性能通常不如 GROUP BY + HAVING 直接。

尤其当表有几百万行时,GROUP BY 能利用索引(如果分组字段有索引),而自关联的 EXISTS 很容易触发全表扫描。

  • 复合索引有用:CREATE INDEX idx_name_phone ON users(name, phone) 能加速 GROUP BY name, phone
  • MySQL 8.0+ 和 PostgreSQL 支持 COUNT(*) OVER (PARTITION BY ……),但会多返回冗余行,不适合“只看重复项”场景

遇到 NULL 值时 COUNT 和 GROUP BY 怎么算

NULLGROUP BY 中被视为相同值:所有 NULL 会归到同一组;COUNT(*) 会统计这组里的行数,但 COUNT(列名) 会忽略该列的 NULL

所以如果你查 email 是否重复,而很多记录 email IS NULL,那 GROUP BY email 可能返回一行 NULL, 500——这不是业务意义上的“重复邮箱”,而是 500 个空值被合并了。

  • 排除空值再查重复:WHERE email IS NOT NULL GROUP BY email HAVING COUNT(*) > 1
  • 想单独看空值有多少条?SELECT COUNT(*) FROM users WHERE email IS NULL
  • PostgreSQL 里可用 GROUP BY email IS NULL, email 把 NULL 和非 NULL 拆开,但多数情况没必要

性能差、卡住?先看执行计划和索引

没索引的 GROUP BY 在大表上可能慢得像卡死,特别是文本字段(如 TEXT 类型)参与分组时。

执行 EXPLAIN(MySQL)或 EXPLAIN ANALYZE(PostgreSQL)看有没有用上索引、是否出现 Using temporary; Using filesort

  • 避免对函数结果分组:GROUP BY UPPER(name) 通常无法走索引,先建函数索引或改用生成列
  • 小表(
  • SQL Server 用户注意:ANSI_NULLS OFF 会影响 NULL 分组行为,生产环境建议保持默认 ON
复杂点在于 NULL 的语义和索引覆盖范围,这两个地方最容易漏看,一跑就慢或结果不对。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-23发表,共计1326字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources