直接查某字段所有值的出现次数应使用GROUP BY+COUNT(),如SELECT department, COUNT() FROM employees GROUP BY department;漏写GROUP BY会报错或返回错误结果,COUNT(department)在department为分组键且非空时等效,含NULL时GROUP BY自动归为一组,COUNT(*)仍准确计数。

直接查某字段所有值的出现次数用 GROUP BY + COUNT(*)
这是最基础也最常用的分布统计方式,适用于你想知道“每个具体值分别出现了多少次”的场景。比如查 department 字段里 “技术部” 出现 127 次、“销售部” 出现 89 次等。
关键点在于:必须把目标字段放进 GROUP BY,且 COUNT(*) 统计的是每组的行数,不是去重个数。
-
SELECT department, COUNT(*) AS cnt FROM employees GROUP BY department—— 正确,按部门分组计数 - 漏写
GROUP BY department会报错(除非 MySQL 在 ONLY_FULL_GROUP_BY 关闭状态下返回随机一行) - 写成
COUNT(department)和COUNT(*)效果一样,因为department是分组键,不可能为 NULL(除非该字段本身允许 NULL 且真有空值) - 如果字段含 NULL,
GROUP BY会把所有 NULL 归为同一组,COUNT(*)照常计数,无需额外处理
只想要不同值的总个数,别用 GROUP BY
如果你问题其实是“这个字段一共有多少种取值”,比如“公司总共设了多少个部门”,那就该用 COUNT(DISTINCT department),而不是套 GROUP BY 再数行数。
原因很实际:GROUP BY 返回的是明细列表,结果集可能上千行;而 COUNT(DISTINCT ...) 只返回一个数字,IO 和网络开销小得多,尤其在大表上差别明显。
-
SELECT COUNT(DISTINCT department) FROM employees—— 直接得总数,快且省资源 - 误写成
SELECT COUNT(*) FROM (SELECT DISTINCT department FROM employees) t也能对,但多一层子查询,优化器不一定能完全消除,不必要 - MySQL 5.7+ 对
COUNT(DISTINCT)有哈希优化,但字段值过多(如千万级唯一值)仍可能临时磁盘排序,注意监控Created_tmp_disk_tables
COUNT(CASE WHEN ...) 统计指定值的频次,别写 ELSE 0
当你要在同一行里并列统计几个固定值的出现次数(比如“胜”“负”“平”各几次),常用 COUNT(CASE WHEN ... THEN 1 END)。这里最容易踩的坑是加 ELSE 0。
因为 COUNT() 只统计非 NULL 值,加了 ELSE 0 后,每行都产出一个 0 或 1,COUNT 会把所有 0 都算进去,导致结果全是总行数。
- ✅ 正确:
COUNT(CASE WHEN result = '胜' THEN 1 END) AS win_cnt - ❌ 错误:
COUNT(CASE WHEN result = '胜' THEN 1 ELSE 0 END) AS win_cnt—— 这会让win_cnt等于总记录数 - 想用
SUM替代也行:SUM(CASE WHEN result = '胜' THEN 1 ELSE 0 END),这时ELSE 0是安全的 - MySQL 支持布尔表达式直接求和:
SUM(result = '胜'),更短,但可读性略低,且部分旧版本对类型隐式转换敏感
按区间或模式分组统计时,GROUP BY 表达式要显式写出
比如统计年龄分段(0-18、19-35、36-60)、手机号前三位归属地、或时间按小时聚合,GROUP BY 后不能只写别名,得写完整表达式。
否则在严格模式(如 PostgreSQL、MySQL 8.0+ 默认)下会报错:「Expression #1 of SELECT list is not in GROUP BY clause」。
- ✅ 正确:
SELECT FLOOR(age/10)*10 AS age_decade, COUNT(*) FROM users GROUP BY FLOOR(age/10)*10 - ❌ 错误:
SELECT FLOOR(age/10)*10 AS age_decade, COUNT(*) FROM users GROUP BY age_decade—— 别名不能用于GROUP BY - 字符串模式同理:
GROUP BY SUBSTR(phone, 1, 3),不能写GROUP BY area_code(即使前面定义了该别名) - 若表达式复杂,可先用 CTE 提前计算,再 GROUP BY,提升可读性和复用性
GROUP BY —— 尤其当结果集远小于原表行数时,优化器可能放弃索引,直接走全表扫描。这点比函数写法选择更值得优先检查。

















