窗口函数(Window Functions)用于在 不分组 的情况下对查询结果中的数据进行计算。不同于 GROUP BY
,窗口函数不会对结果进行聚合,而是对 每一行 数据进行计算,并且可以基于某个 窗口(window) 定义计算范围。
语法结构:
窗口函数() OVER (
[PARTITION BY 分区列]
[ORDER BY 排序列]
[ROWS | RANGE 选项]
)
PARTITION BY
:对数据进行分区,类似 GROUP BY
,但不会影响行的显示。ORDER BY
:定义窗口内的计算顺序。ROWS | RANGE
:定义窗口的范围(可选)。用于对数据进行排名:
RANK()
:排名,相同值会获得相同排名,排名不连续。DENSE_RANK()
:密集排名,相同值排名相同,排名连续。ROW_NUMBER()
:行号,数据按顺序编号,且不会出现重复。示例:
SELECT id, name, score,
RANK() OVER (ORDER BY score DESC) AS rank_num,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank_num,
ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num
FROM students;
计算某些列的累计值:
SUM() OVER ()
:累计求和AVG() OVER ()
:累计平均值COUNT() OVER ()
:累计计数MAX() OVER ()
/ MIN() OVER ()
:最大/最小值示例:
SELECT id, name, salary,
SUM(salary) OVER (PARTITION BY department ORDER BY id) AS running_total
FROM employees;
用于访问当前行的前一行、后一行或某个固定偏移的行:
LAG(column, offset, default) OVER ()
:取前 offset
行数据,默认为 NULL
。LEAD(column, offset, default) OVER ()
:取后 offset
行数据,默认为 NULL
。FIRST_VALUE(column) OVER ()
:取窗口内的第一行值。LAST_VALUE(column) OVER ()
:取窗口内的最后一行值。NTH_VALUE(column, N) OVER ()
:取窗口内的第 N
行值。示例:
SELECT id, name, salary,
LAG(salary, 1, 0) OVER (ORDER BY id) AS prev_salary,
LEAD(salary, 1, 0) OVER (ORDER BY id) AS next_salary
FROM employees;
默认情况下,窗口函数的计算范围是 整个分区(如果有 PARTITION BY
)。但 ROWS
和 RANGE
选项可以进一步细化窗口的范围。
ROWS
ROWS
直接指定 行数 进行计算。
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
SUM() OVER (PARTITION BY xxx)
)。示例:
SELECT id, name, salary,
SUM(salary) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS rolling_sum
FROM employees;
计算当前行及前 2 行的累积工资总和。
RANGE
RANGE
按 数值范围 计算,通常与 ORDER BY
一起使用。
RANGE BETWEEN INTERVAL 3 DAY PRECEDING AND CURRENT ROW
示例:
SELECT id, name, order_date, amount,
SUM(amount) OVER (ORDER BY order_date RANGE BETWEEN INTERVAL 3 DAY PRECEDING AND CURRENT ROW) AS sum_last_3_days
FROM orders;
计算过去 3 天的订单金额总和。
函数类型 | 作用 | 示例 | 计算范围 |
---|---|---|---|
SUM() |
聚合 | SUM(salary) GROUP BY department |
组内整体 |
SUM() OVER() |
窗口 | SUM(salary) OVER (PARTITION BY department ORDER BY id) |
逐行计算 |
示例:
-- 使用 GROUP BY 计算部门工资总和(结果少于原始行数)
SELECT department, SUM(salary) FROM employees GROUP BY department;
-- 使用窗口函数计算部门工资总和(结果和原始行数相同)
SELECT id, name, department, salary,
SUM(salary) OVER (PARTITION BY department) AS department_total
FROM employees;
案例:计算累计销售额占比
WITH sales_ranked AS (
SELECT order_id, customer, amount,
SUM(amount) OVER () AS total_sales,
SUM(amount) OVER (ORDER BY amount DESC) AS running_total
FROM sales
)
SELECT *, (running_total / total_sales) AS percentage FROM sales_ranked;
计算累计销售额占总销售额的比例,帮助分析 80/20 规则(帕累托分析)。
OVER()
语法决定窗口范围:
PARTITION BY
进行分区;ORDER BY
控制计算顺序;ROWS
/ RANGE
进一步控制计算范围。RANK()
、DENSE_RANK()
、ROW_NUMBER()
SUM()
、AVG()
、COUNT()
LAG()
、LEAD()
、FIRST_VALUE()
窗口函数是 数据分析 和 复杂查询 的强大工具,掌握它能极大提升 SQL 处理能力!