SQL窗口分析函数使用详解系列三之偏移量类窗口函数
2024年04月29日
60
1.综述本文以HiveSQL语法进行代码演示。对于其他数据库来说同样也适用,比如SparkSQL,FlinkSQL以及Mysql8,Oracle,SqlServer等传统的关系型数据库。本节介绍Hive窗口分析函数中的第三类窗口函数:偏移量类窗口函数。在实际的应用场景中,顾名思义,偏移量分析函数主要应用于求解和指定偏移数据的差值。例如和上一行数据差值,和下一行数据差值。有什么实际意义呢?例如,每行数据是天粒度的,

1.综述

本文以HiveSQL语法进行代码演示。

对于其他数据库来说同样也适用,比如SparkSQL,FlinkSQL以及Mysql8,Oracle,SqlServer等传统的关系型数据库。

本节介绍Hive窗口分析函数中的第三类窗口函数:偏移量类窗口函数。

在实际的应用场景中,顾名思义,偏移量分析函数主要应用于求解和指定偏移数据的差值。例如和上一行数据差值,和下一行数据差值。

有什么实际意义呢?例如,每行数据是天粒度的,那么上下行的差值计算就是前后天的数据增长量或者减少量,比left join,right join的方式更为简单,效率更高。

1.1 偏移量类窗口函数

lead() over();lag() over();first_value() over();


1.2 窗口函数语法

分析函数 over(partition by 列名 order by 列名 rows between 开始位置 and 结束位置)

具体解析

over()括号内为空时,是直接进行计算。

其中partition by 列名是按指定列进行分组,进而进行计算。

最后的order by 列名 是按照指定列进行排序,进而进行计算。

1.3 基础数据准备

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 '用户信息测试临时表'

数据预览

idclientgenderconstellationagepvchat_num
1ios0处女座291743
2ios1双鱼座262632
3android1双鱼座3523239
4ios1水瓶座32573
5ios1射手座33676
6ios1双子座36815
7ios1狮子座29684
8ios1狮子座28193
9ios0射手座324792
10ios1白羊座2625536

2.各偏移量函数的使用

2.1 lag

  • 功能

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_infowhere id <= 10order by id;

数据结果

idclientagelag_1_age
1ios2910
2ios2629
3android3510
4ios3226
5ios3332
6ios3633
7ios2936
8ios2829
9ios3228
10ios2632

可以看到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

2.2 lead

  • 功能

和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_infowhere id <= 10order by id;

数据结果

idclientagelead_2_age
1ios2932
2ios2633
3android3510
4ios3236
5ios3329
6ios3628
7ios2932
8ios2826
9ios3210
10ios2610

如上,我把偏移量设置为2,可以看到id为9和10的向下两行没有数据。

  • 拓展使用

和lag使用场景一致,很多场景lag和lead都可以互换,需要设置排序是正序或者倒序的区别。

2.3 first_value

  • 功能

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_infowhere id <= 10order by id;

数据结果

idclientagemin_age
1ios2926
2ios2626
3android3535
4ios3226
5ios3326
6ios3626
7ios2926
8ios2826
9ios3226
10ios2626

可以看到当前ios客户端的最小年龄为26,android客户端最小年龄为35.

  • 拓展使用

这样查有什么用呢?

例如可以进一步求解当前用户年龄和最小年龄或者最大年龄的差值。

如果是其他例如销售数据,或者活跃数据等,就更加有实用意义了。

总之,SQL窗口分析函数能够支持我们在更多的场景直接进行数据处理,进而更加深入和高效的进行数据分析