1、函数写法
函数名(参数) OVER (PARTITION BY子句 ORDER BY子句 ROWS/RANGE子句)
由三部分组成: 函数名:如sum、max、min、count、avg等聚合函数以及lead、lag行比较函数等; over:
关键字,表示前面的函数是分析函数,不是普通的集合函数; 分组子句:over关键字后面挂号内的内容;
分析子句又由下面三部分组成: PARTITION BY :分组子句,表示分析函数的计算范围,不同的组互不相干; ORDER BY:
排序子句,表示分组后,组内的排序方式; ROWS/RANGE:窗口子句,是在分组(PARTITION
BY)后,组内的子分组(也称窗口),此时分析函数的计算范围窗口,而不是PARTITON。窗口有两种,ROWS和RANGE;
-
PARTITION BY 子句:
- 这是可选的。
- 它用于将数据集分成不同的分区,每个分区可以有自己的窗口函数计算。
- 例如,如果你有一个按部门分组的员工列表,并想为每个部门的员工分配一个序号,你可以使用
PARTITION BY
来指定部门。
-
ORDER BY 子句:
- 这是必需的。
- 它定义了在窗口函数应用之前,数据应如何排序。
- 你可以根据一个或多个列来排序。例如,你可以根据员工的入职日期来排序。
-
ROWS/RANGE 子句:
- 这是定义窗口函数计算的行范围的参数。
ROWS
:指定一个明确的行数范围。例如,你可以指定从当前行开始并包括之前的5行。RANGE
:基于列值来定义范围。例如,你可以指定从当前行开始并包括到相同列值的最后一行。
开窗函数中的ROWS和RANGE子句用于定义窗口的范围,即函数将在哪些行上执行计算。这两个子句有一些关键的区别:
-
ROWS子句:
- ROWS子句定义了一个明确的行数范围,它基于当前行来指定范围的开始和结束。
- 范围的大小是固定的,并且与当前行无关。
- 当你使用ROWS子句时,通常会使用诸如“UNBOUNDED PRECEDING”和“CURRENT ROW”之类的值来定义范围的开始和结束。例如,如果你指定“ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW”,则函数将在从第一行到当前行的所有行上执行计算。
-
RANGE子句:
- RANGE子句基于列值来定义范围。
- 范围的大小是动态的,并基于当前行的值来调整。
- 当使用RANGE子句时,通常会使用诸如“CURRENT ROW”之类的值来定义范围的开始,而范围的结束是基于列值的。例如,如果你指定“RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING”,则函数将在从当前行到结果集末尾的所有行上执行计算,其中每行的范围基于列值来定义。
总结:
- ROWS子句定义了一个基于行数的固定范围,而RANGE子句则基于列值来定义动态范围。
- 在使用ROWS子句时,你需要指定范围的开始和结束行号。而在使用RANGE子句时,你需要指定范围的开始行号和结束列值。
- 根据你的数据和需求,你可以选择适当的子句来执行所需的窗口函数计算。
以下详细的描述并且准确地解释了SQL中开窗函数中的ROWS和RANGE子句及其用法。
1. current row:当前行。
2. unbounded:表示无限的范围,例如在排序中表示从最前面或最后面的记录开始。
3. unbounded preceding:表示区间的第一行,通常与聚合函数一起使用,如计算总和或平均值。
4. unbounded following:表示区间的最后一行,常用于分组的结尾部分。
5. unbounded preceding and unbounded following:针对当前所有记录的前一条、后一条记录,分组中的所有记录。
6. preceding:在之前的行,n preceding:当前行之前的n行。
7. following:在之后的行,n following:当前行之后的n行。
8. rows between:用于定义一个明确的行数范围,如“rows between unbounded preceding and current row”表示从第一行到当前行的数据。
9. range between:基于列值的范围,如“range between current row and 350 following”表示从当前行到当前行数据+350的范围内的数据。
10. range between preceding and following:定义一个基于列值的动态范围,如“range between 5 preceding and 5 following”表示当前行数据幅度减5加5后的范围内的数据。
以下是一些实际性的案例,展示了如何使用开窗函数的ROWS和RANGE子句:
- 案例一:计算每个部门的员工工资总额
假设有一个名为"employees"的表,其中包含员工的信息和工资。现在要计算每个部门的员工工资总额。
SELECT department, | |
name, | |
salary, | |
SUM(salary) OVER (PARTITION BY department) as total_salary | |
FROM employees; |
在这个例子中,我们使用PARTITION BY子句将数据分成不同的部门,然后使用SUM函数计算每个部门的员工工资总额。通过将SUM函数与OVER子句结合使用,我们可以轻松地计算每个部门的工资总额。
2. 案例二:计算每个员工的累计销售额
假设有一个名为"sales"的表,其中包含销售数据和销售人员的名字。现在要计算每个销售人员的累计销售额。
SELECT name, | |
sale_date, | |
sale_amount, | |
SUM(sale_amount) OVER (PARTITION BY name ORDER BY sale_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cumulative_sales | |
FROM sales; |
在这个例子中,我们使用PARTITION BY子句按销售人员名字分组数据,并使用ORDER BY子句按销售日期排序。然后,我们使用SUM函数计算每个销售人员的累计销售额,通过指定ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW来定义窗口范围,包括从第一行到当前行的所有行。
3. 案例三:计算每个员工的销售排名
假设有一个名为"sales"的表,其中包含销售数据和销售人员的名字。现在要计算每个销售人员的销售排名。
SELECT name, | |
sale_amount, | |
RANK() OVER (ORDER BY sale_amount DESC) as sales_rank | |
FROM sales; |
在这个例子中,我们使用RANK函数计算每个销售人员的销售排名。通过指定ORDER BY子句按销售金额降序排序,RANK函数将为每个销售人员分配一个排名值。使用OVER子句定义窗口范围,以便RANK函数在整个结果集上执行计算。