SUM() OVER 本身不溢出,溢出源于INT类型隐式计算导致中间结果超限;解决方法是提前将输入列转为BIGINT等更大类型,并显式指定ORDER BY确保累计顺序。
SUM() OVER 本身不会溢出,但当你对 INT 列(比如订单金额为 INT)做累计求和时,中间结果仍按 INT 计算,一旦超过 2147483647 就会截断或报错(取决于数据库)。PostgreSQL 会报 integer out of range,SQL Server 可能静默溢出,MySQL 5.7+ 默认也报错。
关键不是窗口语法,而是**输入表达式的类型决定了聚合的计算类型**。
解决方法很简单:提前把参与累计的列转成更大容量类型:
CAST(amount AS BIGINT) 或 amount::BIGINT
BIGINT,但你还加了其他 INT 常量(如 + 1),也要一并转: CAST(amount AS BIGINT) + CAST(1 AS BIGINT)
SUM(CAST(amount AS BIGINT)) OVER (ORDER BY id) —— 这里 CAST 放在 SUM 内部是正确且必要的;放在外面(如 CAST(SUM(amount) AS BIGINT))就晚了,溢出已发生ORDER BY 子句时,SUM() OVER () 是全表总和(非累计),且不同数据库行为不一致:PostgreSQL 允许但结果无序,SQL Server 要求显式 ORDER BY 或 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。
实操建议:
ORDER BY,例如:SUM(CAST(amount AS BIGINT)) OVER (ORDER BY created_at, id)
id)避免排序不确定性SUM() OVER (ORDER BY x RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 看似自然,但 RANGE 在值重复时会合并多行(比如多个相同 created_at),导致累计值“跳变”,且多数数据库无法高效索引 RANGE 窗口。
更稳更快的做法:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(这是默认行为,可省略)ORDER BY 列有索引,尤其是复合排序字段(如 (created_at, id))LATERAL JOIN + 子查询替代复杂窗口,但仅当 EXPLAIN ANALYZE 确认窗口变慢时才动手ERROR 1064。MySQL 8.0+ 才支持,但默认开启严格模式(sql_mode 含 STRICT_TRANS_TABLES),此时 INT 溢出会直接中断查询。
检查与修复步骤:
SELECT VERSION();
SELECT @@sql_mode;
STRICT_*,溢出即报错;若没有,则可能静默截断为 2147483647 或 -2147483648
SUM(CAST(amount AS DECIMAL(20,2))) OVER (ORDER BY id),DECIMAL 避免整数溢出,也适配金额类业务语义OVER。