ROWS 与 RANGE 窗口帧
掌握基于行的窗口帧与基于值的窗口帧之间细微且常被考查的差异
ROWS 与 RANGE 窗口帧 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
面试官重点考察的区别
当您能够写出累计总额后,自然的后续问题就是:“ROWS 和 RANGE 在窗口框架中有什么区别?” 这是衡量中级水平的一个明确指标。许多候选人每天使用框架,却从未注意到这两个关键词的行为并不相同。
二者都定义了聚合函数所能看到的行集合,但对这个集合的计量方式有根本区别。掌握这一点,您就能脱颖而出。
ROWS 按物理行计数
ROWS 是按位置计数的。ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 的字面意思是:当前行加上有序序列中紧邻其上方的两行物理行。
它不在乎相邻行是否具有相同的 ORDER BY 值。三行就是三行,仅此而已。这种框架方式几乎总是适用于移动平均值和严格的累计总额。
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS rows_sum
FROM sales;RANGE 按值计数
RANGE 是按值计算的。它会包含所有 ORDER BY 值落在当前行值的逻辑范围内的行,而不是按行数计数。
最重要的后果是:使用 RANGE 时,所有在 ORDER BY 值上相同的行都会被视为一个同值行分组。它们都会获得相同的框架,因此结果也相同。
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS range_sum
FROM sales;揭示区别的同值示例
假设两笔销售都发生在 2024-03-02,金额分别为 30 和 40;在此之前,2024-03-01 有一笔金额为 100 的销售。
- 使用 RANGE 到 CURRENT ROW:两个 03-02 行属于同值行,因此都显示 100 + 30 + 40 = 170。
- 使用 ROWS 到 CURRENT ROW:第一个 03-02 行显示 130,第二个显示 170,因为每一行都会逐次将框架扩展一个位置。
相同的数据,不同的数字。这种在同值行上的差异正是问题的核心。
默认值为何是 RANGE
请回忆一下,没有明确指定框架时,OVER (ORDER BY ...) 默认使用 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。
这意味着,直接写出的累计总额会默默使用 RANGE。在排序键唯一时,它与 ROWS 完全相同,因此问题会被隐藏。一旦出现重复的排序值,累计总额就会悄悄地将同值行合并在一起。这就是经验丰富的工程师会明确写出 ROWS 的原因。
带数值偏移量的 RANGE
RANGE 可以接受数值偏移量,而不仅仅是 UNBOUNDED。在日期列或数值列上,RANGE BETWEEN 7 PRECEDING AND CURRENT ROW 会包含值与当前值相差不超过 7 个单位的每一行。
应用于日期时,这会生成真正的“最近 7 天”窗口,能够正确跳过缺失的日期;而 ROWS 7 PRECEDING 会不考虑间隔,直接取前面的 7 个行。了解这一细微差别是很有分量的回答。
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW
) AS last_7_days
FROM sales;ROWS 不考虑间隔
反过来,ROWS 完全不理解数据中的间隔。如果您的销售表缺少周末数据,ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 会覆盖 7 个已记录的日期,实际可能跨越两个日历周。
因此,选择取决于您的意图:最近 N 条记录表示使用 ROWS;最近 N 个数值单位(天、美元)表示使用带偏移量的 RANGE。
方言支持的实际情况
严谨的面试回答会指出不同数据库之间的支持差异:
- PostgreSQL 支持带偏移量的
RANGE(从 v11 开始),并且完整支持ROWS。 - SQL 服务器 支持
ROWS和RANGE,但RANGE只支持UNBOUNDED/CURRENT ROW,不支持数值偏移量。 - MySQL 8 同时支持两者,但支持的
RANGE偏移类型有限。
如果无法使用数值 RANGE 偏移量,可以通过自连接或生成日历来模拟。提到这一点可以体现您对生产环境的了解。
GROUPS:第三种模式
还有一种鲜为人知的第三种窗口框架模式:GROUPS。它统计的是同值组,而不是行或数值。GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW 会包含当前同值组以及前一个同值组。
它很少是必需的,但当别人问“还有其他窗口框架模式吗?”时提到它,可以体现真正的深入理解。PostgreSQL 11 及更高版本以及其他少数数据库支持它。
SELECT
sale_date,
amount,
SUM(amount) OVER (
ORDER BY sale_date
GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW
) AS two_day_groups
FROM sales;可以背诵的判断规则
把整个主题浓缩成一句您可以在面试中说出来的话:
“如果我指的是固定数量的物理行,就使用 ROWS;如果我指的是排序值的逻辑范围,就使用 RANGE;还要记住,并列值会使两者产生差异,因为默认 RANGE 会将相等值归为一组。”
这一句话就能完整而自信地回答这个问题。
并排比较
在同一个查询中同时使用两种框架,可以直观看到它们的差异。在包含重复日期的数据上运行此查询,并逐行比较两列。
日期唯一时,两列会完全一致;日期并列时,RANGE 列会在同值行之间重复相同的总计,而 ROWS 列会逐步增加。
SELECT
sale_date,
amount,
SUM(amount) OVER (ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS rows_total,
SUM(amount) OVER (ORDER BY sale_date
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS range_total
FROM sales;快速检查
在默认窗口框架下,两行的 ORDER BY 值相同。会发生什么?
总结:ROWS 与 RANGE
ROWS 统计物理行;RANGE 根据排序列的逻辑值进行统计,并将并列值归为同值行。默认的 OVER (ORDER BY ...) 窗口框架是 RANGE,这就是为什么直接写出的累计总计可能会将重复的排序值归并在一起。
对于“最近 N 条记录”和不受间隔影响的移动窗口,请选择 ROWS;对于尊重间隔的“最近 N 天/美元”,请使用带偏移量的 RANGE。知道 GROUPS 的存在会是加分项。接下来,我们将应用 ROWS 框架来构建移动平均值。
常见问题解答
「ROWS 与 RANGE 窗口帧」课时是免费的吗?
是的 — 「ROWS 与 RANGE 窗口帧」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「ROWS 与 RANGE 窗口帧」这节课中我会学到什么?
掌握基于行的窗口帧与基于值的窗口帧之间细微且常被考查的差异 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「ROWS 与 RANGE 窗口帧」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用窗口帧计算累计和
- ROWS 与 RANGE 窗口帧
- 滑动窗口移动平均值
- 累计分布与占总量百分比