33 COUNT、SUM 与 AVG
聚合函数会对多行计算出一个值。最常见的五种——count、sum、avg、min、max——是基础函数。它们处理 NULL 的方式略有不同:count(*) 统计每一行,包括含 NULL 的行;count(col) 统计 col 的非 NULL 值;sum/avg/min/max 完全忽略 NULL。还有几十种其他函数(stddev、string_agg、array_agg、bool_and、bool_or、jsonb_agg……),每种聚合函数都有自己的行为:例如,array_agg 和 jsonb_agg 会保留 NULL 输入。
本章要点
count(*)、count(col)与count(DISTINCT col)的区别sum、avg、min、max处理数值及其他类型- 聚合函数如何处理 NULL
- 使用
string_agg和array_agg构建列表 - 使用
FILTER (WHERE ...)为每个聚合设置条件
示例
count(*) 统计行数——快速而清晰。count(col) 会跳过 col 的 NULL 值;如果你想知道“有多少行的 email 非 NULL”,这就是正确的选择。count(DISTINCT col) 会先去重;因为必须先物化去重后的集合,所以更慢。
sum 返回总和;如果没有行则返回 NULL(不是 0——这很令人意外,但符合标准)。没有行时,avg 返回 NULL;对于整数输入,avg 返回 numeric,因为整数的平均值很少还是整数。min 和 max 适用于任何可排序的内容,包括文本和时间戳。
string_agg 和 array_agg 是 PostgreSQL 的“连接值”聚合函数——当你想生成列表时,它们正是合适的工具。聚合内部可选的 ORDER BY 控制连接顺序;默认的无序行为无法保证顺序。
FILTER (WHERE ...) 是 SQL 标准规定的、为单个聚合应用条件的方式。它取代了旧式的 sum(CASE WHEN cond THEN x END) 写法——结果相同,但清楚得多。
运行示例
运行方式:
常见陷阱
- 对零行求
sum时,返回NULL而不是0。如果需要 0,请使用COALESCE(sum(x), 0)。 - 整数列上的
avg会产生numeric结果;如果想显示四舍五入后的值,可以把它包在round中。 count(col)跳过 NULL 是一个特性,但会让初学者感到意外。count(*)统计行数;其他形式都是“非 NULL 计数”。- 不使用
GROUP BY的聚合会将整个结果聚合为一行。使用GROUP BY则每组得到一行(下一课介绍)。
在一次扫描中组合聚合函数和 FILTER,即可同时得到许多统计结果。SELECT count(*), count(*) FILTER (WHERE is_active), avg(amount) FILTER (WHERE status = 'paid'), max(created_at) FROM ... 只扫描一次,却能给出许多答案。
给 fruits 增加一个价格列:ALTER TABLE fruits ADD COLUMN price numeric(10,2);(然后用 UPDATE 修改一些价格),再对它运行 sum、avg、min、max。然后试试 SELECT string_agg(name, ', ' ORDER BY id DESC) FROM fruits;,看看顺序反过来了。
下载
SQL 文件:count-sum-avg.sql · 全部示例文件 · 准备工作