不能直接用group by,因为它会压缩行数、丢失明细;而sum() over(partition by customer_id order by order_date)可保留每条订单并计算客户累计消费,缺order by则得组内总和而非滚动累加。

为什么不能直接用 GROUP BY?
GROUP BY 会压缩行数,原始明细全丢掉——比如你有一张订单表,想算每个客户的累计消费额,但又得保留每条订单的日期、金额、商品名。这时候 GROUP BY 就不顶用,它只给你客户ID和总和两列。
SUM OVER 的基本写法和分区逻辑
SUM() OVER() 是窗口函数,不改变行数,只在指定范围内叠加计算。关键在 PARTITION BY:它定义“按什么分组求和”,但不聚合行。
- 要按客户汇总:用
PARTITION BY customer_id - 要算从第一行到当前行的滚动和:加
ORDER BY order_date和ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - 如果只要每个客户的总和(非滚动),
ORDER BY可省略,结果每行都显示该客户的全额
示例:
SELECT order_id, customer_id, amount, SUM(amount) OVER (PARTITION BY customer_id) AS total_by_customer FROM orders;
ORDER BY 在 OVER 中到底影响什么?
没写 ORDER BY 时,SUM() OVER (PARTITION BY ...) 对每个分区所有行求全量和,结果每行都一样;一旦加上 ORDER BY,就变成“有序窗口”,默认行为是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,也就是滚动累加。
- 漏写
ORDER BY却想要滚动和 → 每行值相同,不是你要的“逐行累计” - 写了
ORDER BY但没声明ROWS范围 → 大多数数据库(如 PostgreSQL、SQL Server)仍按默认滚动;但 MySQL 8.0+ 也遵循,而旧版 MySQL 不支持窗口函数 - 想算“当前行前后两行之和”?就得显式写
ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING
常见报错和兼容性注意点
遇到 ERROR: window function not supported in this context,大概率是用了不支持窗口函数的老版本数据库(如 MySQL
- MySQL 用户必须确认版本 ≥ 8.0.2,且不能在
WHERE或GROUP BY子句中直接引用窗口函数别名(得用子查询或 CTE) - PostgreSQL 中,
OVER ()里不能出现聚合函数,比如SUM(SUM(x)) OVER (...)会报错 - 如果
PARTITION BY字段有 NULL,不同数据库处理不一致:PostgreSQL 把 NULL 视为同一组,MySQL 8.0 也是;但有些引擎可能跳过或拆成多组
真正容易被忽略的是:窗口函数的执行顺序晚于 WHERE 和 GROUP BY,但早于 ORDER BY 和 LIMIT。这意味着你不能用 WHERE total_by_customer > 1000 直接过滤——得套一层子查询。











