必须将数据库兼容级别设为160才能使用WINDOW子句;执行SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME()确认当前级别,若≤150则用ALTER DATABASE YourDB SET COMPATIBILITY_LEVEL = 160升级,注意不可降级且可能影响类型转换行为。

必须先把数据库兼容级别设为 160,否则直接报错 Incorrect syntax near 'WINDOW'——这不是写法问题,是 SQL Server 根本不识别这个关键字。
怎么确认并升级兼容级别?
执行前先查当前级别:
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME()
如果返回值是 150 或更低,就得升级:
ALTER DATABASE YourDB SET COMPATIBILITY_LEVEL = 160
- 升级后无法降级回
150或更低,操作前务必备份并测试旧查询逻辑 - Azure SQL 数据库和托管实例默认已是
160,但本地部署的 SQL Server 2022 实例仍默认为150 - 升级可能影响隐式类型转换行为,尤其在
ORDER BY中含表达式时
WINDOW 子句必须放在哪儿?
它只能紧接在 FROM(含 JOIN、WHERE)之后、GROUP BY / HAVING / ORDER BY 之前。放错位置会直接语法报错。
✅ 正确示例:
SELECT dept_id, salary,<br> ROW_NUMBER() OVER w AS rn,<br> AVG(salary) OVER w AS avg_sal<br>FROM employee<br>WHERE status = 'active'<br>WINDOW w AS (PARTITION BY dept_id ORDER BY salary DESC)
- ❌ 把
WINDOW放在SELECT列表之后、FROM之前 → 报错 - ❌ 在 CTE 外部定义
WINDOW w AS ...,然后期望 CTE 内部能引用 → 不生效,CTE 是独立作用域 - ❌ 窗口名
w和已有表别名或列名冲突 → SQL Server 可能静默覆盖,导致语义错乱
什么情况下 WINDOW 才真能简化代码?
它只复用“完全一致”的窗口定义:分区字段、排序字段及方向、帧范围(ROWS/RANGE)三者全部相同。稍有差异就无法共用。
- 一个写
ORDER BY ts DESC,另一个写ORDER BY ts ASC→ 必须两个窗口 - 一个用
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,另一个用RANGE CURRENT ROW→ 不能共用 -
PARTITION BY YEAR(order_date)vsPARTITION BY order_date→ 表达式不同,不匹配 - 只在一个函数里用了
OVER w,另一个仍手写完整OVER (PARTITION BY ...)→ 白定义,没复用
容易被忽略的关键点
WINDOW 子句是编译期优化:SQL Server 只解析一次窗口结构,执行计划中只存一份元数据。但它不会改变运行逻辑——所有 OVER w 最终都会展开成等价的完整 OVER (...)。如果你的 PARTITION BY + ORDER BY 没索引支撑,照样大排序、溢出到 tempdb。真正省事的前提,是同一查询中至少两个窗口函数共享完全相同的定义。










