窗口函数(Window Function)是SQL中用于在查询结果的某个"窗口"或"子集"上执行计算的功能。它们通常与OVER()
子句一起使用,允许在不改变行数的情况下对数据进行聚合、排序或分析。窗口函数不会像GROUP BY
那样将多行合并为一行,而是保留原始行的同时进行计算。
常见的窗口函数包括以下几类:
1. 聚合窗口函数
在窗口内执行聚合操作,例如:
-
SUM()
:计算窗口内某列的总和。 -
AVG()
:计算窗口内某列的平均值。 -
MIN()
:计算窗口内某列的最小值。 -
MAX()
:计算窗口内某列的最大值。 -
COUNT()
:计算窗口内的行数。
sql
SELECT
employee_id,
salary,
SUM(salary) OVER (PARTITION BY department_id) AS department_total_salary
FROM employees;
这会计算每个部门的工资总和,同时保留每个员工的原始行
2. 排序窗口函数
根据窗口内的排序规则为每行分配一个值,例如:
-
ROW_NUMBER()
:为窗口内的每一行分配一个唯一的行号。 -
RANK()
:为窗口内的每一行分配排名,相同值会有相同的排名,后续排名会跳过。 -
DENSE_RANK()
:与RANK()
类似,但不会跳过后续排名。 -
NTILE(n)
:将窗口内的行分成n
个桶,并为每行分配桶号。
sql
SELECT
employee_id,
salary,
RANK() OVER (ORDER BY salary DESC) AS salary_rank
FROM employees;
这会根据工资从高到低为员工分配排名
3. 分析窗口函数
用于计算窗口内的相对值或变化,例如:
-
LAG()
:获取窗口中当前行之前的某一行的值。 -
LEAD()
:获取窗口中当前行之后的某一行的值。 -
FIRST_VALUE()
:获取窗口内第一行的值。 -
LAST_VALUE()
:获取窗口内最后一行的值。
sql
SELECT
employee_id,
salary,
LAG(salary, 1) OVER (ORDER BY salary) AS previous_salary
FROM employees;
这会获取当前行前一行(按工资排序)的工资值
4. 窗口定义
窗口函数的核心是OVER()
子句,它定义了窗口的范围。常见的窗口定义方式包括:
-
PARTITION BY
:将数据分组,窗口函数在每个分组内独立计算。 -
ORDER BY
:指定窗口内的排序规则。 -
ROWS
或RANGE
:定义窗口的物理或逻辑范围(例如前N行、后N行、当前行到末尾等)
sql
SELECT
employee_id,
salary,
AVG(salary) OVER (PARTITION BY department_id ORDER BY hire_date ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_avg
FROM employees;
这会计算每个部门中,按入职日期排序后,当前行及其前后一行的工资平均值
应用场景
窗口函数常用于以下场景:
-
计算累计值(如累计销售额)。
-
计算移动平均值(如过去3个月的平均值)。
-
排名和分组分析(如部门内工资排名)。
-
比较当前行与前一行或后一行的值(如环比分析)
sql
SELECT
employee_id,
department_id,
salary,
SUM(salary) OVER (PARTITION BY department_id) AS dept_total,
AVG(salary) OVER (PARTITION BY department_id) AS dept_avg,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank,
LAG(salary, 1) OVER (ORDER BY hire_date) AS prev_salary
FROM employees;
这个查询会返回每个员工的工资、部门总工资、部门平均工资、部门内工资排名以及前一个员工的工资
窗口函数是SQL中非常强大的工具,能够在不改变数据粒度的情况下进行复杂的分析和计算