必须先用 case when 构造 age_group 字段再 group by;按 birth_date 计算更准确,需用日期函数比较;where 必须在 group by 前以保证性能和语法正确。

用 CASE WHEN + GROUP BY 区分未成年和成年
直接在 GROUP BY 里写年龄判断会报错,必须先用 CASE WHEN 构造分类字段再分组。常见错误是把 age 直接塞进 <code>GROUP BY,数据库不认这种布尔表达式作为分组键。
假设用户表叫 users,年龄字段是 age,标准写法是:
SELECT CASE WHEN age <p>注意:MySQL 和 PostgreSQL 都支持这样写;SQLite 要求 <code>GROUP BY</code> 中的表达式必须和 <code>SELECT</code> 中完全一致(不能用别名),所以不能写 <code>GROUP BY age_group</code>。</p><h3>处理 NULL 或缺失年龄数据</h3><p>如果 <code>age</code> 字段允许为 <code>NULL</code>,上面的查询会把所有空值归到 <code>'成年'</code> 分组(因为 <code>NULL 结果为 <code>FALSE</code>)。这通常不是想要的结果。</code></p>
- 显式加
WHEN age IS NULL THEN '未知'分支 - 或用
COALESCE(age, -1)统一兜底,再判断 - 更稳妥的做法是先过滤:
WHERE age IS NOT NULL,避免污染统计口径
示例(含未知):
SELECT
CASE
WHEN age = 18 THEN '成年'
ELSE '未知'
END AS age_group,
COUNT(*) AS count
FROM users
GROUP BY ... ;
按出生日期计算是否未成年更准确
很多系统存的是 birth_date 而非 age,硬编码 age 会出错——比如生日还没到的人,按年份算满18岁,实际仍未成年。
正确做法是用日期函数动态比对:
- PostgreSQL:
birth_date > CURRENT_DATE - INTERVAL '18 years' - MySQL:
birth_date > DATE_SUB(CURDATE(), INTERVAL 18 YEAR) - SQL Server:
birth_date > DATEADD(YEAR, -18, GETDATE())
然后套进 CASE WHEN,逻辑不变,只是判断条件换成了日期比较。
性能要注意 WHERE 和 GROUP BY 的顺序
如果表很大,又只关心某类用户(比如只统计注册时间在近一年的),千万别把 WHERE 写在 GROUP BY 后面——SQL 不允许。必须把过滤条件放在 GROUP BY 前:
SELECT CASE WHEN age = '2023-01-01' -- 先过滤,再分组 GROUP BY CASE WHEN age <p>否则全表扫描开销巨大。另外,确保 <code>age</code> 或 <code>birth_date</code> 字段上有索引,否则每次都要计算。</p><p>真实场景里,“未成年”定义可能因地区而异(比如日本是20岁),别直接写死18,最好抽成配置或参数。</p>











