SQL:开窗函数(窗口函数)

4、 窗口函数

  • 简单理解,就是对查询的结果多出一列,这一列可以是聚合值,也可以是排序值。
  • 开窗函数一般就是说的是over()函数,其窗口是由一个 OVER 子句 定义的多行记录
  • 开窗函数一般分为两类,聚合开窗函数和排序开窗函数。

简单来说,窗口函数有以下功能:

  • 1)同时具有分组和排序的功能
  • 2)不减少原表的行数
  • 3)语法如下:
<窗口函数> over (partition by <用于分组的列名>
                order by <用于排序的列名> [rows between ?? and ???])

<窗口函数>的位置,可以放以下两种函数:

  • 1) 专用窗口函数,包括后面要讲到的rank, dense_rank, row_number等专用窗口函数。
  • 2) 聚合函数,如sum(). avg(), count(), max(), min()等,rows between…and…

因为窗口函数是对where或者group by子句处理后的结果进行操作,所以窗口函数原则上只能写在select子句中

3)业务需求“在每组内排名”,比如:

排名问题:每个部门按业绩来排名
topN问题:找出每个部门排名前N的员工进行奖励

4.1 排序窗口函数rank

-- 如果我们想在每个班级内按成绩排名,得到下面的结果。
select *,
   rank() over (partition by 班级
                 order by 成绩 desc) as ranking
from 班级表;

我们来解释下这个sql语句里的select子句。rank是排序的函数。要求是“每个班级内按成绩排名”,这句话可以分为两部分:

  • 1)每个班级内:按班级分组

    partition by用来对表分组。在这个例子中,所以我们指定了按“班级”分组(partition by 班级)

  • 2)按成绩排名

    order by子句的功能是对分组后的结果进行排序,默认是按照升序(asc)排列。在本例中(order by 成绩 desc)是按成绩这一列排序,加了desc关键词表示降序排列。

通过下图,我们就可以理解partiition by(分组)和order by(在组内排序)的作用了。

img

group by分组汇总后改变了表的行数,一行只有一个类别。而partiition by和rank函数不会减少原表中的行数

preview

注意事项

  • ​ partition子句可是省略,省略就是不指定分组,只是按成绩由高到低进行了排序。但是,这就失去了窗口函数的功能,所以一般不要这么使用。

  • 窗口函数原则上只能写在select子句中

4.2 rank(), dense_rank(), row_number()区别

select *,
   rank() over (order by 成绩 desc) as ranking,
   dense_rank() over (order by 成绩 desc) as dese_rank,
   row_number() over (order by 成绩 desc) as row_num
from 班级表

得到结果:

img

从上面的结果可以看出:

	rank函数:这个例子中是5位,5位,5位,8位,也就是如果有并列名次的行,会占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,4。

	dense_rank函数:这个例子中是5位,5位,5位,6位,也就是如果有并列名次的行,不占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,2。

	row_number函数:这个例子中是5位,6位,7位,8位,也就是不考虑并列名次的情况。比如前3名是并列的名次,排名是正常的1,2,3,4。

4.3 、排序截取数据lag(),lead(),ntile(),cume_dist()

  • LAG(col,n,default_val):获取往前第n行数据,col是列名,n是往上的行数,当第n行为null的时候取default_val
  • LEAD(col,n, default_val):往后第n行数据,col是列名,n是往下的行数,当第n行为null的时候取default_val
  • NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。
  • cume_dist(),计算某个窗口或分区中某个值的累积分布。假定升序排序,则使用以下公式确定累积分布:
    • 小于等于当前值x的行数 / 窗口或partition分区内的总行数。其中,x 等于 order by 子句中指定的列的当前行中的值。

4.4 聚合函数作为窗口函数

​ 聚和窗口函数和上面提到的专用窗口函数用法完全相同,只需要把聚合函数写在窗口函数的位置即可,但是函数后面括号里面不能为空,需要指定聚合的列名。

我们来看一下窗口函数是聚合函数时,会出来什么结果:

select *,
   sum(成绩) over (order by 学号) as current_sum,
   avg(成绩) over (order by 学号) as current_avg,
   count(成绩) over (order by 学号) as current_count,
   max(成绩) over (order by 学号) as current_max,
   min(成绩) over (order by 学号) as current_min
from 班级表

img

​ 如上图,聚合函数sum在窗口函数中,是对自身记录、及位于自身记录以上的数据进行求和的结果。比如0004号,在使用sum窗口函数后的结果,是对0001,0002,0003,0004号的成绩求和,若是0005号,则结果是0001号~0005号成绩的求和,以此类推。

​ 不仅是sum求和,平均、计数、最大最小值,也是同理,都是针对自身记录、以及自身记录之上的所有数据进行计算,

这样使用窗口函数有什么用呢?

​ 聚合函数作为窗口函数,可以在每一行的数据里直观的看到,截止到本行数据,统计数据是多少(最大值、最小值等)。同时可以看出每一行数据,对整体统计数据的影响。

4.4、over(- - rows between and )

sum()/... over ([partition by 列名] [order by 列名] [rows between ... and ...] )
-- 从起点到当前行数据聚合
between unbounded preceding and current row 
-- 往前2行到往后1行的数据聚合
between 2 preceding and 1 following 
  • rows必须跟在Order by 子句之后,对排序的结果进行限制,使用固定的行数来限制分区中的数据行数量。
    • OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。
    • CURRENT ROW:当前行
    • n PRECEDING:往前n行数据
    • n FOLLOWING:往后n行数据
    • UNBOUNDED:起点,unbounded preceding 表示从表数据的起点unbounded following表示到后面的终点
select name,subject,score,
sum(score) over() as sum1,
sum(score) over(partition by subject) as sum2,
sum(score) over(partition by subject order by score) as sum3, 
-- 由起点到当前行的窗口聚合,和sum3一样
sum(score) over(partition by subject order by score rows between unbounded preceding and current row) as sum4, 
-- 当前行和前面一行的窗口聚合
sum(score) over(partition by subject order by score rows between 1 preceding and current row) as sum5,
-- 当前行的前面一行和后面一行的窗口聚合
sum(score) over(partition by subject order by score rows between 1 preceding AND 1 following) as sum6,
-- 当前和后面所有的行
sum(score) over(partition by subject order by score rows between current row and unbounded following) as sum7
from t_fraction;

+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
| name  | subject  | score  | sum1  | sum2  | sum3  | sum4  | sum5  | sum6  | sum7  |
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
| 孙悟空   | 数学       | 12     | 359   | 185   | 12    | 12    | 12    | 31    | 185   |
| 沙悟净   | 数学       | 19     | 359   | 185   | 31    | 31    | 31    | 104   | 173   |
| 猪八戒   | 数学       | 73     | 359   | 185   | 104   | 104   | 92    | 173   | 154   |
| 唐玄奘   | 数学       | 81     | 359   | 185   | 185   | 185   | 154   | 154   | 81    |
| 猪八戒   | 英语       | 11     | 359   | 80    | 11    | 11    | 11    | 26    | 80    |
| 孙悟空   | 英语       | 15     | 359   | 80    | 26    | 26    | 26    | 49    | 69    |
| 唐玄奘   | 英语       | 23     | 359   | 80    | 49    | 49    | 38    | 69    | 54    |
| 沙悟净   | 英语       | 31     | 359   | 80    | 80    | 80    | 54    | 54    | 31    |
| 孙悟空   | 语文       | 10     | 359   | 94    | 10    | 10    | 10    | 31    | 94    |
| 唐玄奘   | 语文       | 21     | 359   | 94    | 31    | 31    | 31    | 53    | 84    |
| 沙悟净   | 语文       | 22     | 359   | 94    | 53    | 53    | 43    | 84    | 63    |
| 猪八戒   | 语文       | 41     | 359   | 94    | 94    | 94    | 63    | 63    | 41    |
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+

<think>嗯,用户想知道Hive SQL开窗函数ROWS BETWEEN的用法,需要示例和语法说明。首先我得回忆一下Hive的开窗函数相关知识,特别是窗口子句的部分。 ROWS BETWEEN应该用于定义窗口的框架范围,也就是在分区内确定当前行的计算范围。常见的用法比如计算移动平均、累计求和等。语法结构应该是在OVER子句中使用ROWS BETWEEN来指定起始和结束位置。 比如,用户可能想了解如何指定当前行之前的若干行,或者之后的行,比如UNBOUNDED PRECEDING表示分区的开始,CURRENT ROW是当前行,UNBOUNDED FOLLOWING是分区的结尾。还有像n PRECEDING和n FOLLOWING这样的相对位置。 接下来需要给出具体的示例,比如按日期排序,计算最近三天的销售额平均,这时候就需要ROWS BETWEEN 2 PRECEDING AND CURRENT ROW。或者累计求和的话,用ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。 还要注意和RANGE BETWEEN的区别,ROWS是物理行,RANGE是逻辑值范围。这部分可能需要简单提一下,避免用户混淆。 另外,用户提供的引用里提到了Hive的开窗函数如SUM、RANK、ROW_NUMBER等,所以可以结合这些函数来举例。例如,用SUM配合ROWS BETWEEN来做累计求和,或者AVG计算移动平均。 需要注意语法是否正确,比如OVER子句中的PARTITION BY和ORDER BY的位置,以及ROWS BETWEEN的位置是否正确。比如示例中的写法是否符合Hive SQL的标准。 可能还需要提醒用户在使用时注意性能问题,因为窗口函数在处理大数据时可能会有性能影响,尤其是在没有适当分区的情况下。 最后,生成相关问题的时候,可以考虑窗口函数的其他子句、与GROUP BY的区别、性能优化,以及不同函数的结合使用等。</think>### Hive SQL开窗函数ROWS BETWEEN用法说明 #### 一、语法结构 在Hive SQL中,`ROWS BETWEEN`用于定义窗口函数的作用范围,需配合`OVER()`子句使用: ```sql 窗口函数() OVER ( PARTITION BY 列1, 列2... ORDER BY 排序列 ROWS BETWEEN 起始位置 AND 结束位置 ) ``` **核心参数说明**: - **UNBOUNDED PRECEDING**:窗口起点为分区第一行 - **n PRECEDING**:当前行前n行 - **CURRENT ROW**:当前行 - **n FOLLOWING**:当前行后n行 - **UNBOUNDED FOLLOWING**:窗口终点为分区最后一行 #### 二、使用示例 1. **移动平均计算**(近3天销售额平均) ```sql SELECT order_date, sales, AVG(sales) OVER ( PARTITION BY product_id ORDER BY order_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS moving_avg FROM sales_table ``` 2. **累计求和**(从首行到当前行累计) ```sql SELECT employee_id, month, salary, SUM(salary) OVER ( PARTITION BY employee_id ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS cumulative_sum FROM salary_table ``` 3. **前后范围统计**(当前行前后各1行) ```sql SELECT time, value, MAX(value) OVER ( ORDER BY time ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) AS neighbor_max FROM sensor_data ``` #### 三、与RANGE BETWEEN的区别 | 类型 | 计算方式 | 适用场景 | |------------|--------------------------|------------------------------| | ROWS | 按物理行数划分 | 明确行数的窗口(如移动平均)| | RANGE | 按数值范围划分 | 按数值区间划分(如时间范围)| #### 四、注意事项 1. 必须指定`ORDER BY`才能使用`ROWS BETWEEN` 2. 窗口范围定义会影响计算结果准确性 3. 大数据量场景需注意分区字段选择[^4]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值