窗口函数能在不改变数据行结构的前提下,基于分组或排序对数据进行动态聚合,是实现累计计算、滑动窗口、排名分析等复杂场景的核心技术。如果你还没有接触过窗口函数,建议先通过 PostgreSQL 官方文档搭建基础认知:从窗口函数入门教程理解核心概念,到窗口函数完整语法掌握基础用法,再通过窗口函数调用规范了解底层机制,这三步能为深入学习奠定基石。
- 3.5. 窗口函数 http://www.postgres.cn/docs/current/tutorial-window.html
- 9.22. 窗口函数 http://www.postgres.cn/docs/current/functions-window.html
- 4.2.8. 窗口函数调用 http://www.postgres.cn/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS
本文聚焦窗口函数的 “灵魂组件”——frame_clause
,针对ROWS、RANGE、GROUPS三种帧定义模式,通过13个示例的程序代码、数据结果展示和详细的解析说明,帮你突破 “文档看得懂,写代码就懵” 的瓶颈。无论你是想厘清物理行偏移与逻辑值范围的本质区别,还是掌握分组滑动计算的高阶技巧,这些示例都能让你直观理解语法规则,真正将窗口函数转化为数据处理的高效武器。
一、基础概念与测试数据准备
1. 什么是frame_clause?
frame_clause
用于在窗口分区内定义一个子集(窗口帧),窗口函数仅对该子集中的行生效。语法结构为:
OVER (
[PARTITION BY ...]
ORDER BY ...
[frame_clause]
)
其中frame_clause
有三种模式:RANGE
、ROWS
、GROUPS
,分别对应不同的行范围定义逻辑。
2. 测试数据创建
CREATE TABLE public.test_data (
id INT,
score INT, -- 用于排序的数值列(测试RANGE/ROWS)
value TEXT -- 用于分组的文本列(测试GROUPS)
);
INSERT INTO public.test_data(id, score, value) VALUES
(1, 60, 'A'),
(2, 70, 'A'),
(3, 70, 'B'),
(4, 80, 'B'),
(5, 80, 'C'),
(6, 90, 'C');
-- 按score排序后的数据顺序
SELECT * FROM public.test_data ORDER BY score;
id | score | value
----+-------+-------
1 | 60 | A
2 | 70 | A
3 | 70 | B
4 | 80 | B
5 | 80 | C
6 | 90 | C
二、ROWS模式:基于物理行偏移的绝对位置
1. 核心规则
- 偏移量:
offset
表示物理行的数量,必须为非负整数。 - 行范围:以当前行为中心,按
ORDER BY
排序后的物理行位置计算偏移。 - 示例语法:
ROWS BETWEEN <start> AND <end> -- 显式范围 ROWS <offset> PRECEDING -- 从当前行前offset行到当前行(默认end为CURRENT ROW) ROWS UNBOUNDED PRECEDING -- 默认,从分区开始到当前行
2. 案例演示
示例1:当前行 + 前后1行
SELECT
id, score,
COUNT(*) OVER (
ORDER BY score
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) AS row_count
FROM test_data
ORDER BY score;
id | score | row_count | 解释 |
---|---|---|---|
1 | 60 | 2 | – 仅第1行(60)和第2行(70),因为前面没有行,实际范围是1 PRECEDING(不存在)到1 FOLLOWI |