group by 删除重复行生成聚合结果,partition by 保留原始行仅添加计算列;前者用于摘要统计,后者用于明细增强。

GROUP BY 会删行,PARTITION BY 不动原始行
这是最根本的差异。GROUP BY 把 100 行按部门分组后,可能只剩 5 行;而 PARTITION BY dept_id 配合 SUM(salary) OVER (...),输出还是 100 行,只是每行多了一列“本部门总薪资”。
常见错误现象:SELECT name, salary, AVG(salary) FROM emp GROUP BY dept_id —— 报错,因为 name 和 salary 不在 GROUP BY 列表里,也不聚合。
- 要保留每个人信息 + 附带部门平均工资 → 必须用
AVG(salary) OVER (PARTITION BY dept_id) - 只要每个部门一行、显示平均工资 → 用
SELECT dept_id, AVG(salary) FROM emp GROUP BY dept_id -
GROUP BY执行在SELECT之前,窗口函数执行在SELECT阶段,所以它能看到GROUP BY后的聚合结果(但前提是没丢原始行)
OVER() 是必须的,PARTITION BY 不能单独用
PARTITION BY 不是独立语法,它只是 OVER() 的一部分。写成 SELECT * FROM t PARTITION BY col 或 SELECT SUM(x) PARTITION BY y 都会报错,典型错误是 missing window specification。
合法结构只有一种:ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY hire_date)。
-
PARTITION BY可以省略,此时整个结果集视为一个分区,比如COUNT(*) OVER()算全表总行数 - 多字段分区写成
PARTITION BY region, year,等价于先按region再按year嵌套分组 - 别和建表语句里的
PARTITION BY(如 MySQL 表分区)混淆——那是物理存储切分,和窗口函数无关
聚合函数在窗口里必须显式定义窗口范围
在 SELECT 中直接写 SUM(amount),不加 GROUP BY 就报错;但写成 SUM(amount) OVER (PARTITION BY user_id) 就合法。关键区别在于:窗口函数里的聚合函数必须明确作用范围。
常见错误:SELECT user_id, SUM(amount) OVER (PARTITION BY user_id), COUNT(*) FROM orders —— 这里的 COUNT(*) 没加 OVER(),会返回全表行数,不是每个用户的订单数。
- 想算每个用户的订单数?得写
COUNT(*) OVER (PARTITION BY user_id) - 想算滚动 7 天销量?用
AVG(sales) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) -
GROUP BY不支持ROWS BETWEEN,这是窗口函数独有的能力
性能和 NULL 处理容易被忽略
GROUP BY 通常触发哈希分组或排序,内存压力大;PARTITION BY 看似轻量,但多个不同 PARTITION BY 或 ORDER BY 的窗口函数,可能导致同一张表被扫描多次——尤其在 PostgreSQL 和 SQL Server 中明显。
NULL 值行为也不同:PARTITION BY col 默认把所有 NULL 归为一个分区;而 ORDER BY col 在窗口中,MySQL 把 NULL 排最后,PostgreSQL 排最前,且无法用 NULLS FIRST 统一控制(MySQL 不支持该语法)。
真正难的不是语法,而是判断:你要的是压缩后的摘要,还是带明细的增强视图。选错就等于重写逻辑。











