窗口函数与 GROUP BY 怎么选
需要保留明细行、做组内对比时用窗口函数;只需要每组的汇总值时用 GROUP BY 更直接。判断标准很简单:输出行数是明细行数还是组数。两者也能写进同一条查询,但要清楚执行顺序是先分组聚合、后开窗计算。
基本信息
| GROUP BY | 输出行数等于组数,非聚合列必须出现在分组键里 |
|---|---|
| 窗口函数 | 带 OVER,输出行数等于明细行数 |
| 执行顺序 | WHERE → 分组与聚合 → 窗口函数 → ORDER BY → LIMIT |
| 组合使用 | 窗口函数可以作用在聚合结果上,例如 SUM(SUM(x)) OVER () |
| 性能 | 窗口函数需要排序,数据量大时关注排序内存 |
| 选择原则 | 只要汇总值用 GROUP BY,要明细加组内对比用窗口函数 |
两种写法对比
两种写法对比
-- GROUP BY:每组一行汇总
SELECT dept_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept_id;
-- 窗口函数:保留每一行,并附上组内均值用于对比
SELECT id, dept_id, salary,
AVG(salary) OVER (PARTITION BY dept_id) AS avg_salary,
salary - AVG(salary) OVER (PARTITION BY dept_id) AS diff
FROM employees; -- 输出行数仍是明细行数两者组合的写法
两者组合的写法
-- 先分组求每组总量,再用窗口函数算占比
SELECT dept_id,
SUM(salary) AS dept_total,
ROUND(100.0 * SUM(salary) / SUM(SUM(salary)) OVER (), 2) AS pct
FROM employees
GROUP BY dept_id
ORDER BY pct DESC; -- 内层 SUM 是聚合,外层 OVER 才是窗口两者对比
| 维度 | GROUP BY | 窗口函数 |
|---|---|---|
| 输出行数 | 等于组数 | 等于明细行数 |
| 保留列 | 只能输出分组键与聚合值 | 可以保留全部列 |
| 典型用途 | 汇总报表 | 组内排名、占比、环比 |
| 排序需求 | 分组通常隐含排序 | OVER 里的 ORDER BY 决定窗口顺序 |
| 同时使用 | 同一查询不同层级可以 | 注意嵌套层级与语义 |
典型使用场景
- 只要总量与均值:用 GROUP BY 出汇总表
- 要明细行加组内均值:用窗口函数一次算出
- 算占比:分组后配合 SUM(…) OVER () 取全局合计
- 组内排名与取前几名:用 RANK 或 ROW_NUMBER
- 环比与差值:用 LAG、LEAD
- 去重取一行:用 ROW_NUMBER 过滤 rn = 1
窗口函数与聚合函数同名:SUM 带 OVER 是窗口用法,不带 OVER 是聚合。漏写 OVER 会让整张表被聚合成一行,输出从明细变成单值,这是很常见的误查。
混用时层级容易搞错:聚合先算、窗口后算。想对聚合结果再开窗,必须写成 SUM(SUM(x)) OVER () 这种嵌套形式,写成 SUM(x) OVER () 的语义完全不同。