SUM()函数用于计算数值字段总和,自动忽略NULL值;必须配合GROUP BY分组或全表聚合,需确保字段为数值类型,结合COALESCE(SUM(col),0)处理空结果,WHERE筛选在聚合前,HAVING筛选在聚合后。

直接用 SUM() 聚合函数就能算总和,但必须配合 GROUP BY 或整个结果集聚合
如果只写 SELECT SUM(price) FROM orders;,它会返回一行一个数字——整张表 price 字段的总和。但很多人卡在“为什么我加了 WHERE 还是算不对”,其实问题常出在空值或类型上:SUM() 会自动忽略 NULL,但如果字段是字符串(比如存了 "100"),MySQL 可能静默转成 0,而 PostgreSQL 直接报错 ERROR: function sum(text) does not exist。
- 确保字段是数值类型(
INT、DECIMAL等),别用VARCHAR存数字 -
WHERE条件写在SUM()外层,不是函数里面:SUM(CASE WHEN status='paid' THEN amount ELSE 0 END)才能条件求和 - 如果想按用户汇总,必须加
GROUP BY user_id,否则数据库会报错(SQL 标准要求)
SUM() 遇到 NULL 怎么办:默认跳过,但有时你要主动处理
比如订单表里有些 discount 是 NULL,你希望把它们当 0 算进去,直接 SUM(discount) 会少算——因为 NULL 不参与累加。这时候得用 COALESCE 或 IFNULL(MySQL)提前转换:
SELECT SUM(COALESCE(discount, 0)) FROM orders;
-
COALESCE(discount, 0)在 PostgreSQL / SQL Server / 标准 SQL 中通用 - MySQL 可用
IFNULL(discount, 0),更短但不跨平台 - 别用
discount + 0强转,遇到NULL整个表达式还是NULL
想分组再求和?GROUP BY 后字段必须出现在 SELECT 列表里
写 SELECT user_id, SUM(amount) FROM orders GROUP BY user_id; 没问题;但如果你多选了一个没分组的字段,比如 SELECT user_id, order_date, SUM(amount),MySQL 5.7+ 默认拒绝执行(ONLY_FULL_GROUP_BY 开启),PostgreSQL 直接报错。
- 要么把
order_date加进GROUP BY(但会拆散同用户不同日期的记录) - 要么用聚合函数包住它,比如
MAX(order_date)表示“该用户最新下单时间” - 别依赖 MySQL 旧版本的“隐式分组”,行为不可靠,迁移到新环境就崩
性能注意点:SUM() 本身很快,慢通常是因为没走索引
SUM() 是扫描后计算,不产生中间排序,所以瓶颈几乎总是 I/O。如果经常查某条件下的总和(比如 WHERE shop_id = 123),给 shop_id 加索引比优化 SUM() 写法重要得多。
- 复合索引优先考虑查询条件列在前,比如
INDEX(shop_id, created_at)支持WHERE shop_id = ? AND created_at > ?再SUM(amount) -
SUM()无法用覆盖索引跳过聚簇索引查找,除非所有涉及字段都在索引里(包括amount) - 千万级表慎用
SELECT SUM(*)—— 它是语法错误,但有人手抖打出来,数据库会直接报错而不是默默忽略
GROUP BY 的严格性,尤其是从 SQLite 或旧 MySQL 迁移过来时,那些“居然能跑通”的语句往往藏着隐患。

















