window子句仅提升写法复用性与维护性,不优化执行计划;必须位于from之后、select列表之前,且作用域限于当前查询层级,不可跨cte或子查询复用。

WINDOW子句本身不提升运行时复用性,只提升写法复用性和维护性;它不会减少扫描次数或改变执行计划。
WINDOW子句定义位置必须严格在FROM之后、SELECT列表之前
很多人把WINDOW块写在SELECT后面或ORDER BY之后,结果直接报错ERROR: syntax error at or near "WINDOW"。正确顺序只能是:
SELECT ..., SUM(x) OVER w, COUNT(*) OVER w FROM t WINDOW w AS (PARTITION BY a ORDER BY b) ORDER BY ...
-
WINDOW必须紧接在FROM、JOIN等表源之后,不能插在SELECT或WHERE中间 - 多个命名窗口用逗号分隔,如
WINDOW w1 AS (...), w2 AS (...) - 窗口名不能和表别名、列别名冲突,PostgreSQL会报
column "w" does not exist这类误导性错误
复用的前提是所有函数需要完全一致的PARTITION BY + ORDER BY + FRAME
比如你同时要算部门内累计销售额、移动平均、排名,且都按PARTITION BY dept ORDER BY created_at ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW走——这时WINDOW才真正省事。
- 只要有一个函数需要
RANGE而另一个必须ROWS,就得拆成两个窗口名 -
COUNT(*) OVER (PARTITION BY x)和ROW_NUMBER() OVER (PARTITION BY x ORDER BY y)不能共用一个窗口,因为后者强制要求ORDER BY - 隐式类型转换会破坏匹配:如果
PARTITION BY category::text,但主查询里引用的是category(类型为varchar),PostgreSQL可能报column "category" does not exist in window specification
跨CTE或子查询时WINDOW定义不生效
你在外层查询写了WINDOW w AS (...),然后进WITH t AS (SELECT ...)里想用OVER w?不行。命名窗口作用域仅限当前查询层级。
- CTE内部要用窗口,必须在它的
SELECT里重新定义WINDOW - 想“全局复用”,只能把逻辑提到最外层查询,或改用CTE预计算(但注意:这反而可能引入物化开销)
- MySQL 8.0+ 不支持在子查询中使用
WINDOW子句,连语法检查都过不去
真正容易被忽略的是:命名窗口不是“变量”,不能动态拼接,也不能带参数;它只是语法糖,写错一处,所有引用它的函数都会崩。所以别为了抽象而抽象——只在重复≥2次、结构完全一致、且能一眼看出定义位置时才用。











