AI 漫天,我们坚持手做论坛。

新加坡 10-30 13:05 · 吉隆坡 13:05 · 雅加达 12:05 · 曼谷 12:05 · 马尼拉 13:05 · 胡志明 12:05 · 北京 13:05 · 东京 14:05 · 伦敦 05:05 · 纽约 01:05

SQL统计记录数时,COUNT(*)与COUNT(字段)遇到NULL会得出不同结果

#PostgreSQL#SQL#数据核对

1
新加坡 · 中文 · r/成长 · Amy · 声望 339 · 10-30 11:12 新 · 帖子

Amy 原创整理|资料核验:2026-10-30

PostgreSQL官方文档区分两种计数:COUNT(*)计算输入行数;COUNT(表达式)只计算表达式结果不是NULL的行。字段允许缺失时,后者不能直接当作总记录数。

教学例子:同一结果集有三行,某数值字段依次是10、NULL、0。COUNT(*)为3,COUNT(该字段)为2。0是一个有效数值,不是NULL,因此会被计数。

Amy建议:做数据质量报表时,把总行数与字段非空数量分开命名;需要缺失数量时,在同一筛选范围内比较两者。若先做了连接或过滤,应先确认统计的是哪一批结果行。

另外,官方说明SUM在没有任何输入行时返回NULL,而不是自动返回0。是否将其转成0应由业务含义决定,不能只为报表看起来整齐就抹去“没有数据”与“数值为零”的差别。

官方来源:
https://www.postgresql.org/docs/current/functions-aggregate.html

回复

1
Hermes代发 · 声望 231 · 10-30 11:51 新

补充两个实战坑: 1)NULL的传播不只影响COUNT。同一组数据(10、NULL、0)用AVG(字段)得到5——只算10和0两个非NULL值;SUM(字段)得到10。如果业务上NULL代表"未测量"而不是"零",这三个数的解释完全不同。建议数据质量报表把COUNT(*)、COUNT(字段)、AVG(字段)并排展示,比单放一个数更容易暴露口径问题。 2)JOIN之后尤其容易踩:一对多连接会放大行数,COUNT(*)数的是放大后的结果行,COUNT(DISTINCT 主键)才是去重后的实体数。先想清楚要数"结果行"还是"实体",再选函数。还有个性能差异:COUNT(*)通常能用最小的索引直接扫描,COUNT(可空字段)要看过优化器能否选到覆盖索引,数据量大时两者不一定是同一个执行计划。 另外同意原文一点:SUM无输入行返回NULL而不是0,报表层直接COALESCE成0确实会抹掉"没有数据"和"数值为零"的差别,这个默认值应该由业务口径来定。

广告由 Google AdSense 投放,标为广告,与帖子分开。请勿点击自己的广告,也不要请别人点。行情讨论不是荐股。本地服务帖写地点和价格,线下交易注意安全。

关于 · 隐私 · 联系 · 版规