直接用select city, count() from users group by city统计每组行数,count()含null;需排除null则加where city is not null,排序须基于select列或聚合结果。

GROUP BY 单列统计数量的写法
直接用 SELECT + COUNT(*) + GROUP BY 就能完成,不需要子查询或窗口函数。
比如统计用户按城市分布的数量:
SELECT city, COUNT(*) AS count FROM users GROUP BY city;
注意 COUNT(*) 统计的是每组行数,包括 NULL 值;如果只想统计非空的某字段(如 email),得写成 COUNT(email) —— 它会自动忽略 NULL。
WHERE 和 GROUP BY 的执行顺序不能颠倒
WHERE 过滤在分组前发生,HAVING 才用于过滤分组后结果。想先筛出活跃用户再统计城市分布,必须把条件写在 WHERE 里:
- ✅ 正确:
WHERE status = 'active' GROUP BY city - ❌ 错误:把
status = 'active'放到HAVING,会导致先分组再过滤,逻辑错乱
常见错误现象是结果数量远多于预期,或出现本不该存在的分组(比如已注销用户的 city)。
ORDER BY 必须基于 SELECT 列或聚合结果
分组后排序不能直接用原始列名(除非它也在 SELECT 中且被 GROUP BY 覆盖),否则多数数据库会报错,例如:
- ❌
SELECT city, COUNT(*) FROM users GROUP BY city ORDER BY name→name未出现在SELECT或GROUP BY中,报错 - ✅ 改成
ORDER BY city或ORDER BY COUNT(*) DESC就行
MySQL 5.7+ 默认开启 sql_mode=only_full_group_by,这类写法会被严格拦截;老版本可能“侥幸通过”,但结果不可靠。
NULL 值会被单独分到一组
如果 city 字段有 NULL,GROUP BY city 会把它当作一个独立分组,COUNT(*) 照常统计这一组的行数。
想排除 NULL 再统计?加 WHERE city IS NOT NULL;想单独标出缺失值?可以写 COALESCE(city, 'unknown') 替换后再分组。
这个行为容易被忽略,尤其在做报表时发现“总数对不上”——很可能就是 NULL 悄悄占了一组。










