MySQL含JOIN、WHERE子句的查询中WINDOW子句放置位置
MySQL 命名WINDOW子句的正确放置规则
MySQL对SELECT语句中子句的书写顺序有强制要求,WINDOW子句的固定位置是HAVING子句之后、ORDER BY子句之前,和语句中有没有多表关联、WHERE过滤、子查询没有关系。
官方基础示例中WINDOW紧跟FROM子句,只是因为示例没有写WHERE、GROUP BY、HAVING等中间结构,不代表WINDOW必须紧贴FROM放置。
完整的SELECT子句书写顺序
你可以对照这个顺序检查自己的SQL,WINDOW永远在第6个位置:
SELECT字段、聚合函数、窗口函数FROM主表 + 所有关联JOIN(含CROSS JOIN、LEFT JOIN等所有关联逻辑)WHERE行级过滤条件(比如业务中常用的createdAt时间范围过滤)GROUP BY分组字段HAVING聚合结果过滤条件WINDOW命名窗口定义(即需要抽离复用的employeeWindow这类窗口)ORDER BY排序规则LIMIT结果条数限制
业务SQL改造示例
以提到的多表CROSS JOIN、带时间过滤的场景为例:
改造前(内联窗口定义,无法复用)
SELECT e.emp_id, e.name, d.dept_name, s.salary, ROW_NUMBER() OVER (PARTITION BY e.dept_id ORDER BY s.salary DESC) AS rn, RANK() OVER (PARTITION BY e.dept_id ORDER BY s.salary DESC) AS rk, AVG(s.salary) OVER (PARTITION BY e.dept_id) AS dept_avg_sal FROM employee e CROSS JOIN department d CROSS JOIN salary s CROSS JOIN attendance a WHERE e.createdAt BETWEEN '2023-01-01' AND '2023-12-31' AND e.dept_id = d.dept_id AND e.emp_id = s.emp_id AND e.emp_id = a.emp_id ORDER BY e.dept_id, rn
改造后(抽离命名窗口复用,语法正确)
SELECT e.emp_id, e.name, d.dept_name, s.salary, ROW_NUMBER() OVER employeeWindow AS rn, RANK() OVER employeeWindow AS rk, AVG(s.salary) OVER (employeeWindow ORDER BY NULL) AS dept_avg_sal FROM employee e CROSS JOIN department d CROSS JOIN salary s CROSS JOIN attendance a WHERE e.createdAt BETWEEN '2023-01-01' AND '2023-12-31' AND e.dept_id = d.dept_id AND e.emp_id = s.emp_id AND e.emp_id = a.emp_id WINDOW employeeWindow AS (PARTITION BY e.dept_id ORDER BY s.salary DESC) ORDER BY e.dept_id, rn
注意事项
- 嵌套子查询中的命名窗口,必须定义在子查询自身的WINDOW位置,不能跨SELECT层级定义
- 引用命名窗口时,允许在窗口名后追加额外的分区、排序子句覆盖默认规则,适配不同窗口函数的计算需求
- 禁止把WINDOW子句放到JOIN关联段中间、WHERE子句之前、ORDER BY子句之后,这些位置都会触发语法错误
内容的提问来源于stack exchange,提问作者Yanick Rochon
相关产品推荐
相关产品推荐

