首页/数据/SQL 速查/窗口函数与 GROUP BY 的选择
聚合与窗口函数54 条

窗口函数与 GROUP BY 的选择

需要保留明细行、做组内对比时用窗口函数;只需要每组的汇总值时用 GROUP BY 更直接。

SQL 速查数据更新于 2026-10-13

窗口函数与 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 () 的语义完全不同。

易错点

  • 漏写 OVER:SUM(x) 变成聚合,查询只剩一行,明细行全部丢失
  • 在 GROUP BY 里引用非聚合列:报错或取到不确定的值,需要保留明细就改用窗口函数
  • 对超大结果集直接开窗:排序开销大且占用内存,先用 WHERE 缩小数据集
  • 把窗口函数写进 WHERE:它在 WHERE 之后计算,会直接报错,需要包一层子查询或 CTE

数据来源与参考

  • MySQL 8.0 Reference Manual · Window Functions
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌