COUNT(NULLIF(col, NULL))可行,因NULLIF在col为NULL时返回NULL(COUNT忽略),否则返回原值(含空字符串),再除以COUNT(*)得非空比例;需乘1.0防整除截断,且注意NULLIF参数顺序与业务“空”的定义。

用 COUNT 和 NULLIF 计算非空比例为什么可行
NULLIF 在字段值为 NULL 时返回 NULL,否则返回原值;而 COUNT 只统计非 NULL 值。所以 COUNT(NULLIF(col, NULL)) 等价于“该列非空行数”。配合总行数(COUNT(*)),就能算出非空比例。
注意:不能用 COUNT(col) 直接替代 —— 它虽也忽略 NULL,但无法区分“空字符串”和 NULL,而 NULLIF(col, NULL) 保留空字符串(因空字符串 ≠ NULL),更贴近“真实非空语义”。
标准写法与常见错误
正确写法:
SELECT COUNT(NULLIF(name, NULL)) * 1.0 / COUNT(*) AS non_null_ratio FROM users;
容易踩的坑:
- 漏乘
1.0或显式转DECIMAL:整数除整数在 PostgreSQL/SQL Server 中会截断小数,MySQL 5.7+ 默认也做整除 - 误写成
NULLIF(NULL, col):参数顺序反了,永远返回NULL,导致结果恒为 0 - 在
WHERE子句中误加过滤:比如WHERE name IS NOT NULL,会把分母变小,比例失真
扩展:同时排除空字符串和 NULL
如果业务上认为空字符串也算“无效值”,需要一并剔除,就不能只靠 NULLIF(col, NULL):
SELECT COUNT(NULLIF(NULLIF(TRIM(name), ''), NULL)) * 1.0 / COUNT(*) AS non_blank_ratio FROM users;
说明:
-
TRIM(name)先去首尾空格,避免 " " 被当成有效值 - 外层
NULLIF(..., '')把空字符串转为NULL - 内层
NULLIF(..., NULL)保持对原始NULL的处理 - 嵌套顺序不能颠倒:必须先处理空字符串,再处理
NULL,否则NULLIF(NULL, '')无意义
性能与兼容性提醒
NULLIF 是 SQL 标准函数,PostgreSQL、SQL Server、Oracle、MySQL 8.0+ 都支持;但 SQLite 仅支持简单形式,且 COUNT(NULLIF(...)) 在旧版 MySQL(如 5.6)中可能报错。
大表慎用:该计算需全表扫描,且无法走索引加速(除非有函数索引,如 PostgreSQL 的 CREATE INDEX ON t ((name IS NOT NULL)))。若只是检查某列是否“基本不为空”,可先用 LIMIT 抽样估算。
真正难的是定义“空”——是 NULL?空字符串?空白符?零值?业务含义不清时,光套公式没用。

















