本文以HiveSQL语法进行代码演示。
对于其他数据库来说同样也适用,比如SparkSQL,FlinkSQL以及Mysql8,Oracle,SqlServer等传统的关系型数据库。
已更新第一类聚合函数类,点击这里阅读 ①SQL窗口函数系列一之聚合函数类
本节介绍Hive窗口分析函数中的第三类窗口函数:偏移量类窗口函数。
在实际的应用场景中,顾名思义,偏移量分析函数主要应用于求解和指定偏移数据的差值。例如和上一行数据差值,和下一行数据差值。
有什么实际意义呢?例如,每行数据是天粒度的,那么上下行的差值计算就是前后天的数据增长量或者减少量,比left join,right join的方式更为简单,效率更高。
lead() over();
lag() over();
first_value() over();
分析函数 over(partition by 列名 order by 列名 rows between 开始位置 and 结束位置)
具体解析
over()
括号内为空时,是直接进行计算。
其中partition by 列名
是按指定列进行分组,进而进行计算。
最后的order by 列名
是按照指定列进行排序,进而进行计算。
create table if not exists temp.user_info (
`id` bigint comment '用户id',
`client` string comment '客户端',
`gender` int comment '性别,0女1男',
`constellation` string comment '星座',
`age` int comment '年龄',
`pv` bigint comment '访问量',
`chat_num` bigint comment '聊天次数'
) comment '用户信息测试临时表'
数据预览
id | client | gender | constellation | age | pv | chat_num |
---|---|---|---|---|---|---|
1 | ios | 0 | 处女座 | 29 | 174 | 3 |
2 | ios | 1 | 双鱼座 | 26 | 263 | 2 |
3 | android | 1 | 双鱼座 | 35 | 232 | 39 |
4 | ios | 1 | 水瓶座 | 32 | 57 | 3 |
5 | ios | 1 | 射手座 | 33 | 67 | 6 |
6 | ios | 1 | 双子座 | 36 | 81 | 5 |
7 | ios | 1 | 狮子座 | 29 | 68 | 4 |
8 | ios | 1 | 狮子座 | 28 | 19 | 3 |
9 | ios | 0 | 射手座 | 32 | 479 | 2 |
10 | ios | 1 | 白羊座 | 26 | 255 | 36 |
Lag函数用于获取指定列的前n(取决于偏移量的设置)个行的值,按照我们设定的分区以及排序规则。
lag(column_name, offset, default_value) over (partition by partition_col order by order_col)
① column_name
要查询的列名
② offset
要查找的偏移量,即要获取的行数的偏移量,默认为1,例如往前1行或者n行。
③ default_value
一个可选的默认值(当没有找到前一个行时返回的值)
按客户端分组,按id排序,取出上一行的年龄。
select id,client,age,lag(age,1,10) over(partition by client order by id) as lag_1_age from temp.user_info
where id <= 10
order by id;
数据结果
id | client | age | lag_1_age |
---|---|---|---|
1 | ios | 29 | 10 |
2 | ios | 26 | 29 |
3 | android | 35 | 10 |
4 | ios | 32 | 26 |
5 | ios | 33 | 32 |
6 | ios | 36 | 33 |
7 | ios | 29 | 36 |
8 | ios | 28 | 29 |
9 | ios | 32 | 28 |
10 | ios | 26 | 32 |
可以看到id为1的用户没有上一行,所以取到的值为我设置的默认值10.如果不设置默认值,返回null
Id 为2的用户渠道的偏移值是id为1的用户的年龄。
偏移量最常见的使用是当数据最细粒度为天粒度时,查询该用户的前一天行为和今天行为的差值或者相比上一日上涨或者下降百分比等。伪SQL
-- 这里省略了偏移量和默认值
select id,pv,dt,pv-lag_pv as gap_pv -- 当日和上一日的pv差值
from (
select id,pv,dt,lag(pv) over(partition by id order by dt) as lag_pv from temp.user_pv_info
) a
和lag类似,却刚好相反。是取向下的偏移量的值。进而进行差值计算等。
用于获取指定列的后n(取决于偏移量的设置)个行的值,按照我们设定的分区以及排序规则。
lead(column_name, offset, default_value) over (partition by partition_col order by order_col)
① column_name
要查询的列名
② offset
要查找的偏移量,即要获取的行数的偏移量,默认为1,例如往前1行或者n行。
③ default_value
一个可选的默认值(当没有找到前一个行时返回的值)
按客户端分组,按id排序,取出下二行的年龄。
select id,client,age,lead(age,2,10) over(partition by client order by id) as lead_2_age from temp.user_info
where id <= 10
order by id;
数据结果
id | client | age | lead_2_age |
---|---|---|---|
1 | ios | 29 | 32 |
2 | ios | 26 | 33 |
3 | android | 35 | 10 |
4 | ios | 32 | 36 |
5 | ios | 33 | 29 |
6 | ios | 36 | 28 |
7 | ios | 29 | 32 |
8 | ios | 28 | 26 |
9 | ios | 32 | 10 |
10 | ios | 26 | 10 |
如上,我把偏移量设置为2,可以看到id为9和10的向下两行没有数据。
和lag使用场景一致,很多场景lag和lead都可以互换,需要设置排序是正序或者倒序的区别。
first_value
用于返回分组中的第一个值,按指定的排序列。我们在使用中可以根据特定的排序规则来确定和查询获取每个分组的第一个值。
first_value(expression) over(
[partition by 列名1,列名2]
[order by 列名3,列名4]
)
① expression
要获取第一个值的列或者表达式
② partition by
用于指定分组的列
③ order by
用于指定排序的列
查询不同客户端,年龄最小的用户。
select id,client,age,first_value(age) over(partition by client order by age) as min_age from temp.user_info
where id <= 10
order by id;
数据结果
id | client | age | min_age |
---|---|---|---|
1 | ios | 29 | 26 |
2 | ios | 26 | 26 |
3 | android | 35 | 35 |
4 | ios | 32 | 26 |
5 | ios | 33 | 26 |
6 | ios | 36 | 26 |
7 | ios | 29 | 26 |
8 | ios | 28 | 26 |
9 | ios | 32 | 26 |
10 | ios | 26 | 26 |
可以看到当前ios客户端的最小年龄为26,android客户端最小年龄为35.
这样查有什么用呢?
例如可以进一步求解当前用户年龄和最小年龄或者最大年龄的差值。
如果是其他例如销售数据,或者活跃数据等,就更加有实用意义了。
总之,SQL窗口分析函数能够支持我们在更多的场景直接进行数据处理,进而更加深入和高效的进行数据分析。
以上,关于SQL窗口函数的三类就更完了。后续更多以SQL每日一题的方式体现。
感谢阅读。
下一期:还没想好。
按例,欢迎点击此处关注我的个人公众号,交流更多知识。