AVG()配合布尔表达式能算比例,因为SQL标准将TRUE隐式转为1、FALSE转为0,故AVG(condition)等价于满足条件的行数占非NULL结果行数的比例;需注意各数据库对布尔值处理的差异及NULL影响。

AVG() 配合布尔表达式为什么能算比例
因为 SQL 标准中,TRUE 被隐式转为 1,FALSE 转为 0(PostgreSQL、MySQL 8.0+、SQL Server、Oracle、SQLite 均支持),所以 AVG(condition) 实质是统计满足条件的行数占总行数的比例。
注意:MySQL 5.7 及更早版本不直接支持布尔值参与数值计算,需显式用 CASE WHEN 或 IF() 转换;PostgreSQL 对 boolean 类型做 AVG() 会报错,必须先转成 integer。
常见写法示例(以统计每部门中薪资 > 10000 的员工占比为例):
SELECT dept, AVG(CASE WHEN salary > 10000 THEN 1.0 ELSE 0.0 END) AS high_salary_ratio FROM employees GROUP BY dept;
MySQL 中用 IF() 替代 CASE WHEN 更简洁
在 MySQL 里,IF(condition, 1, 0) 比 CASE WHEN 少打不少字,且语义清晰。关键是必须用 1.0 或 0.0(带小数点)来确保结果是浮点数,否则整数除法会导致结果恒为 0 或 1(尤其在旧版本或严格模式下)。
-
AVG(IF(salary > 10000, 1, 0))→ 错!返回整数平均值,可能截断 -
AVG(IF(salary > 10000, 1.0, 0.0))→ 正确,保留小数精度 -
ROUND(AVG(IF(salary > 10000, 1.0, 0.0)), 3)→ 推荐,控制输出位数
PostgreSQL 必须显式转换 boolean 到 numeric
PostgreSQL 不允许对 boolean 直接调用 AVG(),会报错:function avg(boolean) does not exist。必须用 ::int 或 CAST(... AS integer) 强制转换。
正确写法:
SELECT dept, ROUND(AVG((salary > 10000)::int), 3) AS high_salary_ratio FROM employees GROUP BY dept;
注意括号位置:(salary > 10000)::int 是先判断再转整,salary > 10000::int 就变成比较 salary 和整数 10000,语义错误。
NULL 值会影响分母,但通常符合预期
AVG() 默认忽略 NULL,所以如果条件表达式本身产出 NULL(比如 salary 为 NULL 时,salary > 10000 结果是 NULL),这部分行既不计入分子也不计入分母——即分母是“非 NULL 条件结果”的行数。
如果你希望把 NULL 当作 FALSE 处理(即计入分母但不进分子),就得显式覆盖:
AVG(CASE WHEN salary > 10000 THEN 1.0
WHEN salary IS NOT NULL THEN 0.0
ELSE 0.0 END)
这个细节容易被忽略,特别是当字段本身存在大量 NULL 时,比例偏差可能很大。

















