sum溢出发生在聚合内部逐行累加阶段,必须用sum(cast(col as bigint))而非cast(sum(col) as bigint);类型推导只看输入列,不因外层cast改变,所有涉及聚合、having、join、窗口函数的场景均需提前转换。

因为 SUM() 的中间计算过程严格绑定输入列的数据类型,不是结果大了才溢出,而是加法每一步都在小类型寄存器里执行——等你看到报错,累加早已崩了。
为什么 CAST(SUM(col) AS BIGINT) 一定无效
溢出发生在 SUM() 函数内部的逐行累加阶段,数据库按原始列类型(比如 INT)分配固定宽度的计算空间(32 位)。哪怕总和超限后得到一个负值(如 -2147483648),外层 CAST 也无力回天。
- MySQL 5.7+ 中,
SUM(INT)中间结果仍是INT,不因SELECT里的CAST改变 - SQL Server 对
SMALLINT列执行HAVING SUM(col) > 32767会直接报错,因为SUM(SMALLINT)返回类型还是SMALLINT - PostgreSQL 报
integer out of range,也是同一原理:类型推导只看输入,不看外层包装
SUM 溢出的正确写法:CAST 必须包在聚合函数里面
目标是让加法全程运行在更大类型空间中。关键不是“转结果”,而是“换跑道”。
- 正确:
SUM(CAST(amount AS BIGINT))、SUM(CAST(pdfsize AS NUMERIC(20,0))) - 错误:
CAST(SUM(amount) AS BIGINT)、CAST(SUM(pdfsize)/1024/1024 AS NUMERIC) - 如果字段是
UNSIGNED INT,要转UNSIGNED BIGINT,否则隐式符号转换可能引发异常 - 涉及表达式(如
block_id * 8192 + bytes),必须对每个参与运算的项分别CAST,例如:MAX(CAST(block_id AS DECIMAL) * 8192 + bytes)
HAVING 和 JOIN 场景下容易漏掉 CAST
HAVING 子句里的聚合表达式,和 SELECT 一样走原始类型路径。JOIN 后的列还可能因 NULL 或隐式转换导致类型被重解释,CAST 位置失效。
-
HAVING SUM(CAST(salary AS BIGINT)) > 1000000000✅ -
HAVING CAST(SUM(salary) AS BIGINT) > 1000000000❌ - LEFT JOIN 多表后取数值列,建议先用子查询或 CTE 显式
CAST,避免 JOIN 时类型被“污染” - SQL Server 中用
TYPE_NAME(SUM(CAST(col AS BIGINT)))验证中间结果类型,别只信MAX(col)
最常被忽略的是:窗口函数 SUM() OVER、分组聚合、HAVING、表达式计算——这些场景都共享同一套类型推导规则。只要输入列是小整型,没提前 CAST,就随时可能在某次数据增长后突然报错。











