SQL中如何用SUM(OVER)函数实现累加求和?

作者:袖梨 2026-07-12
SUM() OVER()是窗口函数用法,非独立函数,必须写成SUM(column_name) OVER(...);漏字段、错括号或数据库不支持均会报错。

什么是SUM(OVER)?它不是独立函数,而是窗口函数用法

SUM(OVER) 本质是 SUM() 配合 OVER 子句构成的窗口函数,不是单独存在的函数。直接写 SUM(OVER ...) 会报错——必须写成 SUM(column_name) OVER (...)

常见错误现象:ERROR: syntax error at or near "OVER",往往是因为漏了括号内的求和字段,或把 OVER 当成 SUM 的参数。

  • SUM(sales) OVER (ORDER BY date) ✅ 正确:对 sales 按日期累加
  • SUM OVER (ORDER BY date) ❌ 错误:缺少被聚合的列
  • SUM(sales OVER (ORDER BY date)) ❌ 错误:OVER 不能套在括号里当参数

如何写累加(运行总计)?关键看ORDER BY和PARTITION BY

累加的核心是定义“按什么顺序加”和“是否分组重置”。不加 ORDER BYSUM() OVER() 等价于全表总和;加上 ORDER BY 才形成逐行累加。

典型场景:销售日报表中计算截至当日的累计销售额。

  • SUM(amount) OVER (ORDER BY order_date) → 全局按日期递增累加
  • SUM(amount) OVER (PARTITION BY region ORDER BY order_date) → 每个地区内独立累加
  • 如果只写 SUM(amount) OVER (),结果每行都是同一值(全表总和),不是累加

注意:ORDER BY 列必须有确定排序(避免相同值导致非确定性累加),必要时加唯一键如 ORDER BY order_date, id

为什么结果和预期不符?检查空值、重复排序键和框架默认行为

累加结果异常,90% 出现在三类情况:空值参与计算、排序键重复、没意识到默认框架是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

  • NULL 值会被忽略(不影响累加),但如果想把 NULL0 处理,得先用 COALESCE(amount, 0)
  • ORDER BY 字段存在重复(如多笔订单同一天),数据库可能任意打乱这些行顺序,导致累加值“跳变”或不稳定
  • 想改成“包含当前行及前一行”的累加,需显式写 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW,否则始终是“从开头到当前行”

示例(PostgreSQL/MySQL 8.0+/SQL Server):

SELECT   date,  sales,  SUM(sales) OVER (ORDER BY date, id) AS cumsumFROM daily_sales;

不同数据库对SUM(OVER)的支持差异有哪些?

语法一致,但兼容性差别大:MySQL 5.7 不支持,必须 8.0+;SQLite 直到 3.25+ 才支持窗口函数;Oracle 和 SQL Server 支持较早(2005+),但旧版本可能不支持 ROWS 框架子句。

  • 确认版本:SELECT VERSION();(MySQL)、SELECT @@VERSION;(SQL Server)
  • SQLite 用户需检查编译选项是否启用了 ENABLE_WINDOW_FUNCTIONS
  • 如果目标库不支持,替代方案是自连接或变量(如 MySQL 5.7 的 @cumsum := @cumsum + sales),但不可靠且非标准

真正麻烦的不是语法写不对,而是查了半天发现数据库压根不认 OVER —— 动手前先验证环境支持比调逻辑更重要。

相关文章

精彩推荐