SUM 是什么
SUM 对数值列求和,忽略 NULL。它有一个容易被忽视的行为:没有任何行、或者所有行该列都是 NULL 时返回 NULL,而不是 0,报表里通常用 COALESCE 兜底。这与 COUNT 在无数据时返回 0 不同。SUM 还有 DISTINCT 变体 SUM(DISTINCT col),语义是先去重再求和,用之前要先想清楚业务含义。金额求和务必使用 DECIMAL 这类定点类型,浮点累加会累积精度误差。
基本信息
| 作用 | 对数值列求和,忽略 NULL |
|---|---|
| 无数据时 | 返回 NULL,与 COUNT 返回 0 不同 |
| DISTINCT 变体 | SUM(DISTINCT col) 先去重再求和 |
| 类型 | 整数与 DECIMAL 保持精确,FLOAT 与 DOUBLE 是近似值 |
| 配合窗口函数 | SUM(x) OVER (…) 可算累计值与组内合计 |
| 适用平台 | 标准 SQL,MySQL 8.0 与 PostgreSQL 一致 |
典型使用场景
- 金额合计:订单总额、对账金额、月度营收
- 累计求和:滚动余额与累计销量
- 分组汇总:按天、按类目、按渠道求总额
- 占比分母:SUM(x) OVER () 得到全局合计做占比
- 条件求和:只把满足条件的行计入合计
- 核对数据:与上游系统或明细加总的结果比对
示例
示例
SELECT COALESCE(SUM(amount), 0) AS total, # 无数据时给 0
SUM(IF(status = 'paid', amount, 0)) AS paid_total # 条件求和
FROM orders
WHERE created_at >= '2024-05-01'
AND created_at < '2024-06-01';
-- PostgreSQL 的条件求和写法
SELECT SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) AS paid_total
FROM orders;SUM 的行为细节
| 场景 | 结果 | 说明 |
|---|---|---|
| 无匹配行 | NULL | 报表需 COALESCE 兜底 |
| 列全为 NULL | NULL | 不是 0 |
| 部分行该列为 NULL | 忽略这些行 | 不计入也不报错 |
| SUM(DISTINCT col) | 去重后求和 | 语义与直觉可能不同 |
| 含浮点类型 | 近似结果 | 金额应改用定点类型 |
SUM 与 COUNT 在无数据时的返回值不同:一份报表里混用两者时,要分别处理 0 与 NULL,避免前端显示异常。
用 FLOAT 或 DOUBLE 累加金额会产生精度误差,几十万行累加后偏差可见,金额一律用 DECIMAL 或 numeric。
窗口形式的 SUM(x) OVER (ORDER BY d) 默认是从分区开头到当前行的累计值,想算组内总量要省略 ORDER BY。
求和结果要带明确口径:金额保留两位、数量取整、是否包含退款与取消,先把口径写进报表说明再写 SQL,能省掉大量返工。
SUM 的结果类型会随数据一起扩张:整数列在大批量数据上求和可能溢出,注意列类型上限,必要时用更大的整型或 DECIMAL。