count(column_name)只统计非null值,对空字符串、空格、'0'等均计数;需用count(case when trim(col)!='' then 1 end)或nullif实现真非空统计。

COUNT(column_name) 只统计非 NULL 值,不是非空字符串
很多人以为 COUNT(phone) 会跳过 ''(空字符串)和 NULL,其实它只忽略 NULL,对 ''、' '、'0' 全部计数。这是最常踩的坑。
-
COUNT(phone)→ 统计所有phone IS NOT NULL的行,不管值是不是空字符串 -
COUNT(*)→ 统计所有行(含NULL字段) - 想排除空字符串?得显式过滤:
COUNT(CASE WHEN phone != '' AND phone IS NOT NULL THEN 1 END)
用 COUNT + CASE 实现“真非空”统计
真正想统计“有实际内容”的字段(即既不为 NULL,也不为 '' 或纯空白),必须靠 CASE 配合 TRIM()。
- 标准写法:
COUNT(CASE WHEN TRIM(phone) != '' THEN 1 END) - MySQL 中可简写为:
COUNT(NULLIF(TRIM(phone), ''))(NULLIF把空字符串转成NULL,再被COUNT忽略) - PostgreSQL / SQL Server 同样适用
TRIM+CASE;SQL Server 用LTRIM(RTRIM(phone))替代TRIM(旧版本无TRIM)
WHERE 和 HAVING 对 COUNT 结果的影响差异
WHERE 在聚合前过滤行,HAVING 在聚合后过滤分组结果——这个顺序错不得。
- 统计「用户表中手机号非空的总人数」→ 用
WHERE:SELECT COUNT(*) FROM users WHERE TRIM(mobile) != '' - 统计「每个城市里手机号非空的用户数,并只显示大于 10 的城市」→
HAVING才有用:SELECT city, COUNT(*) FROM users WHERE TRIM(mobile) != '' GROUP BY city HAVING COUNT(*) > 10 - 别把
WHERE mobile IS NOT NULL和HAVING COUNT(mobile) > 0混用:后者毫无意义,因为COUNT(mobile)永远 ≥ 0,且分组内至少有一行才会进入HAVING判断
性能注意:函数索引或冗余字段能救慢查询
带 TRIM() 或 CASE 的 COUNT 很难走索引,尤其在大表上可能全表扫描。
- 高频查询「非空手机号数量」?考虑加一个计算列(如 MySQL 5.7+ 的
GENERATED COLUMN)或触发器维护has_mobile BOOLEAN字段 - PostgreSQL 可建函数索引:
CREATE INDEX idx_users_mobile_nonempty ON users ((CASE WHEN TRIM(mobile) != '' THEN 1 END)) - 别依赖
SELECT COUNT(*) FROM t WHERE col != ''看似简单——如果col有大量NULL或空白,优化器未必选对执行计划
NOT NULL 约束?还是应用层认定的“有意义内容”?这两者经常不一致,得先跟产品/前端对齐语义,再决定用 IS NOT NULL 还是 TRIM() != ''。











