OVER子句必须搭配窗口函数使用,单独使用会报错;它定义窗口范围,真正计算由SUM()、COUNT()等函数完成,如SUM(salary) OVER (PARTITION BY dept ORDER BY hire_date)。

OVER子句必须搭配窗口函数才能生效
单独写 OVER 什么也不做,SQL Server 会直接报错。它只是定义“窗口范围”的语法糖,真正干活的是 SUM()、COUNT()、AVG() 这类函数。常见错误是写成 SELECT name, OVER(PARTITION BY dept) FROM emp —— 这语法根本通不过。
正确姿势是:先选一个聚合函数,再用 OVER 给它划作用域。比如按部门算累计工资:
SELECT name, dept, salary,<br> SUM(salary) OVER (PARTITION BY dept ORDER BY hire_date) AS cum_salary<br>FROM emp;
-
PARTITION BY是分组逻辑,类似GROUP BY,但不压缩行数 -
ORDER BY在窗口内排序,影响累计类函数结果;没写则整个分区视为无序集合 - 不写
PARTITION BY就是全表一个窗口,比如全表总和:SUM(salary) OVER ()
PARTITION BY 和 GROUP BY 的行为差异要盯紧
这是最容易混淆的点:GROUP BY 后每组只留一行,PARTITION BY 则保留原始所有行,只是让聚合结果“广播”到每一行。比如部门平均工资:
用 GROUP BY:
SELECT dept, AVG(salary) FROM emp GROUP BY dept;→ 输出 3 行(假设有 3 个部门)
用 OVER:
SELECT name, dept, salary,<br> AVG(salary) OVER (PARTITION BY dept) AS avg_dept_salary<br>FROM emp;→ 输出和原表一样多行,每人旁边都带着自己部门的平均值
- 想补全缺失值?用
AVG() OVER (PARTITION BY ...)比先GROUP BY再JOIN更简洁 - 如果误把
PARTITION BY当成GROUP BY用,会发现结果行数没变,但数值“看起来不对”——其实是对的,只是语义不同
ORDER BY 在窗口里影响 ROWS/RANGE 范围界定
一旦加了 ORDER BY,SQL Server 默认按 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 计算,也就是“从分区开头到当前行”。但这个默认可能不是你想要的。
比如想算“当前行前后各 1 行的平均工资”,就得显式写:
AVG(salary) OVER (<br> PARTITION BY dept <br> ORDER BY hire_date <br> ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING<br>)
-
ROWS按物理行数偏移,RANGE按排序值相同性偏移(值相同时会捆在一起) - 没写
ORDER BY却用了ROWS?报错:The function 'ROW_NUMBER' must have an ORDER BY clause. - 性能上,
ROWS通常比RANGE快,尤其数据量大时
NULL 值在 PARTITION BY 中会被单独分到一组
如果 dept 字段有 NULL,PARTITION BY dept 会把所有 NULL 归为一个独立分区,而不是忽略或合并到其他组。这常导致“明明没填部门的人,却算出了平均工资”这种意外。
验证方法:
SELECT COUNT(*) FROM emp WHERE dept IS NULL;<br>-- 再查窗口结果里 dept 为 NULL 的行,看 avg_dept_salary 是否一致
- 想排除 NULL 参与分区?提前过滤:
WHERE dept IS NOT NULL - 想把 NULL 当作普通值处理(比如归入“未分配”组)?用
COALESCE(dept, 'Unassigned') - 注意
ORDER BY中 NULL 默认排最前(NULLS FIRST),但 SQL Server 不支持该关键字,得靠CASE显式控制
实际写的时候,先想清楚:你要的是“每行带一个汇总值”,还是“压缩成一组一行”——前者用 OVER,后者用 GROUP BY。窗口函数的威力在于不丢行,但代价是容易忽略分区边界和 NULL 的隐式分组。

















