在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

窗口函数

窗口函数读取与当前行相关的一组行,计算一个值,再把它写回当前行。它可以计算累计和、排名,同时保留每个源行;GROUP BY 则将每组缩成聚合结果,改变结果粒度。

OVER 分成三个问题:PARTITION BY 决定哪些行一起计算;内部 ORDER BY 决定计算顺序;函数与适用的 frame 决定当前值读取哪些有序行。窗口内部排序不保证最终返回顺序,需要时还要查询级 ORDER BY。

累计 SUM 如何工作

本课显式指定范围:

SELECT
  id,
  region,
  day,
  amount,
  SUM(amount) OVER (
    PARTITION BY region
    ORDER BY day, id
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  ) AS running_sum
FROM sales
ORDER BY region, day, id;

内部 ORDER BY day, id 决定累计前缀,外部 ORDER BY region, day, id 决定返回顺序。每个当前行的 ROWS 范围从本地区首行开始,到当前行结束,SUM 只累加这些成员的 amount。

窗口函数逐步演示

默认源表故意交错:

idregiondayamount
s1North330
s2South140
s3North130
s4South340
s5North250
s6South210
s7North420

按 region 分区,再按 day、id 排序:North 为 s3 → s5 → s1 → s7,South 为 s2 → s6 → s4。

  1. North 的 s3 读取 [s3],得到 30。
  2. s5 读取 [s3, s5],30 + 50 = 80。
  3. s1 读取 [s3, s5, s1],30 + 50 + 30 = 110。
  4. s7 读取 [s3, s5, s1, s7],30 + 50 + 30 + 20 = 130。
  5. South 从零重新开始,窗口顺序的累计值为 40、50、90。

按行 ID 写回,教学表仍按源顺序排列:

idregiondayamountrunning_sum
s1North330110
s2South14040
s3North13030
s4South34090
s5North25080
s6South21050
s7North420130

这里保持源顺序是为了核对身份,不表示 SQL 在没有外部 ORDER BY 时也保证此顺序。

RANK 与 DENSE_RANK

排名沿用分区和排序,但不使用聚合行范围:

SELECT
  id,
  region,
  amount,
  RANK() OVER (
    PARTITION BY region
    ORDER BY amount DESC
  ) AS rank
FROM sales;

内部 ORDER BY 值相同的行是同级行,得到相同排名。当前按 amount 降序:RANK 为 1 加前面金额严格更大的行数;DENSE_RANK 为 1 加前面不同金额的种数。

North 顺序为 s5(50), s1(30), s3(30), s7(20)。两个 30 都为 2,下一行 RANK=4,因为前面三行;DENSE_RANK=3,因为前面只有两个不同金额。South 为 s2(40), s4(40), s6(10),两个 40 并列,10 的 RANK=3、DENSE_RANK=2。

idRANKDENSE_RANK
s122
s211
s322
s411
s511
s632
s743

宽同级组预设让 West 四行以 90 并列,后两行 RANK 为 5、6,DENSE_RANK 为 2、3,便于看出排名空缺。

窗口函数与 GROUP BY

窗口函数将 n 个源行变为 n 个附加计算列的行;GROUP BY region 将 n 行变成 p 个地区聚合行。默认窗口结果有七行,分组结果只有两行,后者不再保留 s1、s3 等逐行身份。

删掉 PARTITION BY 是另一种改变。分区重置预设中,全局 ORDER BY day, id 为 p2, p3, p1, p4,累计值 10, 110, 210, 215。首个 South 仍为 10,要等两地区共享前缀时才看到错误。正确分区后 North 为 100、200,South 为 10、15。

边界情况

  • 空输入没有分区、范围、同级组或输出,窗口函数不凭空造行。
  • 单行分区的累计范围只有自己,两种排名都为 1。
  • 同级行共享排名,下一不同值才揭示是否跳号。
  • ROWS 按位置定义,若 day 相同而先后会影响中间累计值,可加 id 作为确定性次序。
  • 缺少外部 ORDER BY 时,内部顺序只约束计算,不约束返回展示。

常见错误

  • 认为 PARTITION BY 合并源行,它只划定独立计算范围。
  • 按源表顺序累计,实际应遵循 OVER 内的 ORDER BY。
  • 省略 frame 后假设等于 ROWS。某些默认 RANGE 会把同值行一起纳入,与逐行前缀不同。
  • 用不同值个数算 RANK,那是 DENSE_RANK;RANK 计前面行数,会跳号。
  • 内部有 ORDER BY 就认为返回顺序稳定,需要外层排序。
  • 把讲解工作台当物理排序或缓冲计划。SQL 定义逻辑,优化器选择执行。

模型范围

本课展示逻辑分区、窗口排序、显式前缀 ROWS、同级组、排名空缺、行身份和结果行数。省略执行策略、内存与落盘、排序规则、NULL 顺序、溢出精度、命名窗口、FILTER、其他边界、RANGE、GROUPS、排除子句和方言默认值。隐式 frame 与 NULL 排序应按目标数据库确认。