必须将cast置于聚合函数内部,即sum(cast(col as bigint)),而非cast(sum(col) as bigint),因为溢出发生在中间累加阶段,原始列类型决定计算位宽,外层转换无法挽救已发生的溢出。

SUM() 报“算术溢出”不是数据太大,而是数据库在聚合过程中用错了中间类型——比如 INT 列求和,默认中间类型还是 INT,超 2147483647 就炸,跟最终目标字段类型无关。
为什么 CAST(SUM(col) AS BIGINT) 会失败?
错误写法:CAST(SUM(col) AS BIGINT) 看似合理,但执行顺序是先算 SUM(col)(用原始列类型),再转。如果原始列是 INT,加总过程已经溢出报错,CAST 根本没机会生效。
正确做法必须把 CAST 提前到聚合内部:
- ✅ SUM(CAST(col AS BIGINT))
- ❌ CAST(SUM(col) AS BIGINT)HAVING 子句同样适用该规则:
- ✅
HAVING SUM(CAST(salary AS BIGINT)) > 1000000000 - ❌
HAVING CAST(SUM(salary) AS BIGINT) > 1000000000
不同数据库对中间类型的处理差异
- SQL Server:SMALLINT 列的 SUM() 中间类型仍是 SMALLINT,不是自动升为 INT;MONEY 类型建议直接换 DECIMAL,避免四舍五入失真
- MySQL 5.7+:SUM(INT) 中间计算仍走 32 位,CAST 必须提前介入,否则静默截断(若未开 STRICT_TRANS_TABLES)
- 达梦 / PostgreSQL:同理,MAX(block_id * 8192 + bytes) 溢出,得写成 MAX(CAST(block_id AS DECIMAL) * 8192 + bytes)JOIN 后聚合时容易漏掉的类型陷阱
LEFT JOIN 后取某表数值列做 SUM(),该列可能因 NULL 或隐式转换被重新解释类型。例如:
- LEFT JOIN orders ON u.id = o.user_id
- SUM(o.amount) 中,o.amount 若为 DECIMAL(9,2),但 NULL 参与后可能触发类型收缩或隐式 CAST
解决方案:始终显式包裹,如 SUM(CAST(o.amount AS DECIMAL(18,2))),且确保 WHERE 和 HAVING 中同步使用相同写法
CTE 或子查询里别省 CAST
溢出常发生在嵌套层,而错误堆栈只显示最外层语句,排查成本陡增。 - ❌ 错误示范:WITH agg AS (SELECT user_id, SUM(amount) FROM t GROUP BY user_id) SELECT * FROM agg WHERE total > 1e9;- ✅ 正确写法:
WITH agg AS (SELECT user_id, SUM(CAST(amount AS BIGINT)) AS total FROM t GROUP BY user_id) SELECT * FROM agg WHERE total > 1000000000;
真正麻烦的不是不会加 CAST,而是加完上线才发现某些分组的中间类型比预想的还小——比如两个 DECIMAL(9,2) 相加,结果精度可能被压缩,而你只查了 MAX(col),没验证 SUM() 的中间类型。











