




窗口函数让“既要聚合、又要明细”成为可能,通过OVER()子句在不丢失原始行的前提下实现分组聚合与排序计算,支持LAG/LEAD环比、ROWS BETWEEN滚动计算等高级分析,是高级SQL能力的分水岭。
传统 GROUP BY 一执行,原始行就没了——想看每个员工的工资,又想看他们部门平均工资?得写子查询或自连接。窗口函数直接在 SELECT 里加个 AVG(salary) OVER (PARTITION BY dept),每行都带着自己部门的均值回来,不丢数据、不增行数。
OVER() 漏写或写成空括号,结果变*表窗口(比如全公司平均),而不是按部门算ROW_NUMBER() 或计算累计和时,没 
ORDER BY 会报错或返回不可靠结果LAG() 和 LEAD() 是环比/同比的底层开关做月度销售环比,不用再拼日期逻辑 + 左连接上个月表。一行 LAG(amount) OVER (PARTITION BY region ORDER BY sale_month) 就能拿到上月值,再跟当前行做减法除法就行。
sale_month 有缺失(比如某地区某月没数据),LAG() 会跳过空值取更早的,导致“上月”错位——建议先用 GENERATE_SERIES 或补全月份再开窗LAG(col, 2) 表示取前两行,不是“上个月”,顺序完全依赖 ORDER BY 的列和方向ROWS BETWEEN 控制移动窗口,不是玄学算 7 日滚动销售额?不是靠应用层循环,而是数据库原生支持:SUM(amount) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)。这里 ROWS 看的是物理行序,RANGE 看的是值范围(比如 “过去 7 天” 要用 RANGE INTERVAL '6 days' PRECEDING,但仅 PostgreSQL/Oracle 支持)。
RANGE + INTERVAL,只能用 ROWS + 排序后硬凑天数,遇到重复日期可能不准UNBOUNDED PRECEDING 是安全写法,但别滥用——没 PARTITION BY 时,它会让窗口跨全表,大表易 OOMORDER BY + 窗口框架会触发 filesort,拖慢几倍因为能否用好窗口函数,直接暴露你是在写“能跑就行”的 SQL,还是在构建可维护、可复用、可下推的数据逻辑。它不解决“查不到”的问题,而是解决“查出来没法直接用”的问题——比如运营要一份带排名、带累计、带环比、还保留用户 ID 的明细报表,不用窗口函数就得四张临时表嵌套三层子查询。而一个写对的 OVER() 子句,就是把这四步压进一行表达式里。
真正卡住人的从来不是语法,而是想清楚:我要的“窗口”,到底该按什么分(PARTITION BY)、按什么排(ORDER BY)、框多大(ROWS/RANGE)。这三个条件少一个,结果就偏一点;错一个,整张报表就废掉。