窗口函数能实现“分组合计+保留明细”,因GROUP BY会压缩行数丢失明细,而窗口函数在不减少行数前提下为每行附加计算值,如SUM() OVER(PARTITION BY ...)。

为什么不能直接用 GROUP BY 实现“分组合计 + 保留明细”
因为 GROUP BY 会折叠原始行,每组只返回一行聚合结果,原始明细数据就丢了。你想看每个订单的金额,同时又看到该客户所有订单总金额——这两层信息天然冲突,GROUP BY 无法共存。
窗口函数正是为解决这类“既要分组统计、又要保留原粒度”问题而生的:它不改变行数,只在每行上附加计算值。
用 SUM() OVER(PARTITION BY ...) 添加分组累计字段
这是最常用也最直观的替代方式。核心是把原本写在 GROUP BY 后的分组键,挪到 OVER(PARTITION BY ...) 里。
-
PARTITION BY customer_id表示按客户分组,但不合并行;每行仍保持自己的order_id、amount -
SUM(amount) OVER(PARTITION BY customer_id)会在每一行上补一个“该客户总金额”列 - 支持与普通列混用:
SELECT order_id, amount, SUM(amount) OVER(PARTITION BY customer_id) AS total_by_customer FROM orders - 注意:未加
ORDER BY在OVER中时,SUM 是整组总和;加了则变成累计和(如ORDER BY order_date)
多个聚合指标怎么一起加?用多个窗口函数并列写
一个 SELECT 可以同时调用多个窗口函数,互不影响。不需要子查询或 CTE 就能一次性拿到均值、计数、最大值等。
- 例如:同时要客户订单数、平均金额、最高单笔金额 —— 全部写在 SELECT 列表里即可
COUNT(*) OVER(PARTITION BY customer_id)AVG(amount) OVER(PARTITION BY customer_id)MAX(amount) OVER(PARTITION BY customer_id)- 所有这些都作用于同一行,且不干扰彼此的
PARTITION BY逻辑 - 性能上,多数数据库(PostgreSQL、SQL Server、Oracle、MySQL 8.0+)会对相同
PARTITION BY的多个窗口函数做一次分组扫描,不是各自扫一遍
兼容性陷阱:哪些数据库不支持?旧版本怎么绕?
MySQL 在 5.7 及更早版本完全不支持窗口函数,强行写会报错 ERROR 1064: You have an error in your SQL syntax;SQLite 默认也不支持(除非编译时启用了 ENABLE_WINDOW_FUNCTIONS)。
- 确认版本:
SELECT VERSION()(MySQL)、SELECT sqlite_version()(SQLite) - MySQL 5.7 替代方案:用关联子查询,例如
(SELECT SUM(amount) FROM orders o2 WHERE o2.customer_id = o1.customer_id),但性能差、不能索引优化 - 如果必须用老版本且数据量大,建议先用
GROUP BY写入临时表,再和原表JOIN,比子查询更可控 - PostgreSQL 9.4+、SQL Server 2005+、Oracle 8i+ 都支持,但 Oracle 早期版本对
ORDER BY在窗口中行为略有差异
真正容易被忽略的是排序稳定性:没写 ORDER BY 在 OVER 里时,SUM 结果确定,但如果有 ORDER BY 却没定义唯一排序键(比如只按 amount 排),相同值的行顺序可能每次不同,导致累计和“跳变”。










