最稳妥的做法是COUNT(DISTINCT CASE WHEN ... THEN x END)。它在聚合内部完成条件过滤、去重和计数兼容主流数据库避免WHERE提前删行导致分组数据丢失或子查询逻辑错误。GROUP BY 里怎么数“满足条件的去重值”直接说结论COUNT(DISTINCT CASE WHEN ... THEN x END) 是最稳妥的做法。它把条件过滤、去重、计数三步压进一个聚合表达式语义清晰各数据库MySQL 5.7、PostgreSQL、SQL Server、Oracle都支持。常见错误是先 WHERE 再 GROUP BY —— 这会整个删掉不满足条件的行导致分组丢失其他字段的完整数据也有人想用子查询套 DISTINCT结果要么报错如 MySQL 5.7 的 ONLY_FULL_GROUP_BY要么逻辑错乱比如漏统计空值或重复计数。CASE WHEN status active THEN user_id END注意 ELSE 省略即为 NULL而 COUNT 自动忽略 NULL正好符合“只数满足条件的”需求如果字段本身可能为 NULL比如 user_id 允许为空且你不想把它算进去这个写法天然安全但如果你需要把 NULL 当作一个有效值去重就得显式写 ELSE null_marker别用 SUM(CASE WHEN ... THEN 1 ELSE 0 END) 替代——它不带 DISTINCT纯属计数行数不是去重计数MySQL 8.0 和 PostgreSQL 用 FILTER 能更干净这两个数据库支持聚合函数的 FILTER 子句语义更直白也避免了 CASE 表达式里隐含的 NULL 处理歧义。比如统计每个部门里不同邮箱域名的数量只看已验证邮箱SELECT dept, COUNT(DISTINCT email_domain) FILTER (WHERE verified true)FROM usersGROUP BY dept;对比传统写法SELECT dept, COUNT(DISTINCT CASE WHEN verified true THEN email_domain END)FROM usersGROUP BY dept;两者结果一致但 FILTER 更易读、不易手误漏写 THEN 后的字段不过要注意SQLite 不支持老版本 MySQL别在 COUNT(DISTINCT ...) 里塞复杂表达式比如 COUNT(DISTINCT CONCAT(first_name, -, last_name)) 看似能拼出唯一标识但容易踩坑如果 first_name 或 last_name 是 NULL整个 CONCAT 返回 NULL被 COUNT 忽略——你可能以为人没来其实是名字不全被吃了拼接符 - 若恰好出现在某人姓或名里比如 first_name Jean-Paul会导致两个不同组合撞成同一个字符串性能上每行都要执行字符串拼接再哈希去重比直接对 id 或 email 去重慢不少尤其数据量大时真要拼字段去重优先考虑用 (first_name, last_name) 这样的行构造器PostgreSQL 支持MySQL 8.0 在某些上下文也支持语义明确且 NULL 安全。 Fotor AI Image Generator Fotor 平台的 AI 图片生成器