Skip to content

SQL 窗口函数 详解

所有常见的 SQL 窗口函数以及控制它们的子句,按用途分组:为行排名、查看相邻行、在帧上累计求和、提取首值或末值。每行将函数与一行示例配对。

窗口函数在与当前行相关的各行上计算结果,而不像 GROUP BY 那样把它们折叠。每个窗口函数都以定义窗口的 OVER 子句结尾:PARTITION BY 为行分组,ORDER BY 为行排序,可选的帧限定滑动集合。掌握 OVER 之后,其余的只是词汇。

参考表格 · 27 条目
27 of 27 rows
排名
窗口内每行一个唯一的连续整数。ROW_NUMBER() OVER (ORDER BY total DESC)
带间隔的排名;并列的行共享名次并跳过后续数字。RANK() OVER (ORDER BY total DESC)
无间隔的排名;并列的行共享名次,不跳过任何数字。DENSE_RANK() OVER (ORDER BY total DESC)
将有序窗口切分成 n 个大致相等的桶。NTILE(4) OVER (ORDER BY total DESC)
查看相邻行
向前 n 行的值;不存在该行时用默认值替代。LAG(total, 1, 0) OVER (ORDER BY created_at)
向后 n 行的值;不存在该行时用默认值替代。LEAD(total, 1, 0) OVER (ORDER BY created_at)
窗口聚合
不折叠行的累计或分区总和。SUM(total) OVER (ORDER BY created_at)
累计或分区平均值。AVG(total) OVER (PARTITION BY user_id)
累计或分区行数。COUNT(*) OVER (PARTITION BY user_id)
整个窗口或分区中的最小值。MIN(total) OVER (PARTITION BY user_id)
整个窗口或分区中的最大值。MAX(total) OVER (PARTITION BY user_id)
带 ORDER BY 且帧从起点敞开的 SUM;每行累加到自身为止的所有值。SUM(total) OVER (ORDER BY created_at ROWS UNBOUNDED PRECEDING)
在当前行前后各 n 行的帧上求 AVG。AVG(total) OVER (ORDER BY created_at ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
首值、末值与百分位
窗口排序中的第一个值。FIRST_VALUE(total) OVER (ORDER BY total DESC)
帧中的最后一个值;没有 UNBOUNDED FOLLOWING 时帧止于当前行。LAST_VALUE(total) OVER (ORDER BY total ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
窗口排序中第 n 行的值。NTH_VALUE(total, 2) OVER (ORDER BY total DESC)
行的相对排名,从 0 到 1。PERCENT_RANK() OVER (ORDER BY total)
位于当前行及之前的行所占比例,从 1/n 到 1。CUME_DIST() OVER (ORDER BY total)
OVER 子句
定义每个函数读取的窗口。<fn>() OVER (PARTITION BY user_id ORDER BY created_at)
为每一组行重新开始窗口。PARTITION BY user_id
在每个分区内为行排序。ORDER BY created_at
限定滑动帧的边界,例如从前几行到后几行。ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
按值而非行位置限定帧;CURRENT ROW 包含并列的行,且这是有 ORDER BY 时的默认帧。RANGE BETWEEN 100 PRECEDING AND CURRENT ROW
按 ORDER BY 产生的并列行组限定帧。GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW
将当前行移出帧;EXCLUDE TIES 则改为移除与之并列的行。ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW
为窗口在每个查询中命名一次,供多个 OVER 子句复用。WINDOW w AS (PARTITION BY user_id ORDER BY created_at)
在应用窗口之前,收窄窗口聚合读取的行。SUM(total) FILTER (WHERE status = 'paid') OVER (ORDER BY created_at)