给窗口起个名字
一个查询里多个窗口函数用同一个 OVER 定义时,可以用 WINDOW 子句给窗口命名,再在函数后面引用名称:少写重复的 PARTITION BY 与 ORDER BY,改一处全生效。MySQL 8 与 PostgreSQL 都支持这种写法。
基本信息
| 语法 | WINDOW 名称 AS (定义),一个查询可定义多个 |
|---|---|
| 引用方式 | 在函数后写 OVER 名称 |
| 收益 | 同一查询内复用,修改只需改一处 |
| 能力限制 | 命名窗口不能再改 PARTITION BY;能否追加 ORDER BY 视数据库而定 |
| 作用域 | 仅限当前查询,子查询里要重新定义 |
典型使用场景
- 一次算多个指标,例如组内均值、组内最大值
- 计算与组均值的差值
- 避免重复粘贴同一段窗口定义
- 统一团队 SQL 的窗口写法
- 横向对比不同窗口定义的效果
示例
示例
SELECT id, dept_id, salary,
AVG(salary) OVER w AS dept_avg,
MAX(salary) OVER w AS dept_max,
salary - AVG(salary) OVER w AS diff
FROM employees
WINDOW w AS (PARTITION BY dept_id);
-- 一个查询里可以定义多个命名窗口
SELECT id, dept_id, salary,
AVG(salary) OVER w_dept AS dept_avg,
AVG(salary) OVER w_all AS global_avg
FROM employees
WINDOW w_dept AS (PARTITION BY dept_id),
w_all AS ();能力边界
| 能力 | 是否支持 | 说明 |
|---|---|---|
| 引用命名窗口 | 支持 | 函数后写 OVER 名称即可 |
| 追加 ORDER BY | 视数据库而定 | 部分实现允许在名称后补排序 |
| 再改 PARTITION BY | 不支持 | 分区必须写在名称定义里 |
| 跨子查询复用 | 不支持 | 作用域只在当前查询 |
| 整分区窗口 | 支持 | WINDOW w AS () 表示不分区 |
命名窗口不等于缓存结果:它只是语法层面的复用,函数仍按各自的帧逐行计算,性能和把定义展开写没有本质差别。
作用域只在当前查询:把这套写法搬到子查询里必须重新定义,否则会报找不到窗口名。
命名窗口也能用在聚合窗口函数上:同一查询里同时算组内累计与组内总额,用两个命名窗口比把定义重复写四遍清楚得多。
团队里可以把常用的窗口定义整理成片段随 SQL 一起提交,评审时几秒就能看出分组与排序口径是否一致,比读散落在多处的 OVER 定义快得多。