针对一行数据,输出多行数据,主要用于map,array这种的
根据一个例子来看:
- friends 是一个array数组
- students 是一个map
- address是一个struct
explode函数以array类型数据输入,然后对数组中的数据进行迭代,返回多行结果,一行一个数组元素值。
作用于array:
- arrayCol :array字段的名称
- colName1 :array字段的别名,随便起
举例:
- mapcol :map字段名称
- key1:key的别名 随便起
- value1:value的别名 随便起
举例:
区别:
- posexplode只能用于array,而explode可以用于array,map
- posexplode还会返回元素在集合中的位置
那么,解决的问题到底是什么?
sql语法:
- ⚠️lateral view 一定要在udtf函数的前面
- ⚠️虚拟表别名一定要加,不然会报错
举例:
首先对字段A从小到大进行排序。
1.按照排序后的一行一行作为窗口,从第一行开始,第一行的字段A最小,发现自己是最小的,那就当前行做为第一个窗口,计算结果只有本身,结果返回给第一行。
2.从第二行开始继续寻找,负无穷到当前行的,第二个窗口包含第一行、第二行数据,做范围内运算,sum=第一行的字段A+第二行的字段A,结果返回给第二行。
第三个窗口,包含第一行、第二行、第三行数据,那么计算sum=第一行字段A+第二行字段A+第三行字段A。
以此类推。。。。
最后一行的返回的计算结果一定是所有行字段A的总和
那这跟直接sql写sum()+group by 有什么区别吗?
⭐️区别在于,每行数据都会参与到计算中来,同时得到窗口计算的结果,我们直接写sql语句调用sum()只会返回最终结果,相当于只有最后一个窗口的值。
between相当重要的原因是按照什么样的规则定义窗口。
- unbounded preceding 表示负无穷
- current row 基于行的方式表示当前行,基于值的方式表示当前值
- unbounded following 表示正无穷
- [num] preceding 基于行的方式 表示当前行的前几行,基于值的方式 表示当前值减去num
- [num] following 基于值的方式 表示当前行的后几行,基于值的方式表示当前值加上num
between规则应用的不一样
同样都是between unbounded preceding and cureent now
基于行的含义是负无穷到当前行,而基于值的含义是负无穷到当前值
也就说基于行 会以自己的行 为终点,但是基于值 会 查找某个字段 小于等于自己的,自己的行不一定是终点。
如下图所示:
order_id为1的查找order_date小于等于自己的,只有本身,total_amount为自己
order_id为2的查找order_date小于等于自己的,有order_id为1,order_id为2,order_id为3,total_amount为10+20+10
order_id为3的查找order_date小于等于自己的,有order_id为1,order_id为2,order_id为3,total_amount为10+20+10
如果不开分区,那么窗口的计数从整个数据的开始到结尾
如果开了分区,那么一个分区内窗口计数从分区头到分区尾
说白了,第二个分区的实际数据即使在表的中间,也有可能属于第一个窗口
基于行的语法:
-
字段1,字段2 不用说了,就是显示的字段
-
⭐️ sum(字段3) 是基于窗口做什么操作,这个表示是基于每个窗口对 sum3字段做求和操作
-
⭐️ over()表示是什么样的窗口
字段2:针对字段2进行划分窗口
rows:表示基于行
between unbounded preceding and current row:表示负无穷到最后一行
基于值的语法:
- range:表示基于值
- unbounded preceding and unbounded following: 表示负无穷到正无穷
加分区:
跟基于行 基于值没有关系
- partition by 字段1 表示针对字段1做分区
- 就什么都不加,over(字段)相当于 基于行做窗口,范围是负无穷到正无穷,相当于所有字段作为一个窗口
- over(order by 字段) 排序后基于值做窗口,范围是负无穷到当前行
- ⭐️无论基于行还是基于值, 不加order by,没有任何意义(因为你都不知道上一行和下一行的值有没有关联),做范围内计算也是白瞎
支持以下几种,不再多阐述
max
min
sum
avg
count
分别包括:
lag和lead(不支持自定义窗口):
lag(): 按照 所在行的偏移量 取 前面的第几行
lead(): 按照 所在行的偏移量 取 后面的第几行
first_value和last_value(支持自定义窗口):
- first_value():当前窗口内所有行数据中的最小值
- last_value(): 当前窗口内所有行数据中的最大值
⚠️要注意,lag和lead不能使用自定义窗口,因为已经规定好了具体某一行与当前行作为一个窗口,不能再定义是负无穷到正无穷这样自定义的规则。
lag和lead:
语法:
-
lag() :
-
字段3:结果字段
-
1: 取当前行前面的前1行
-
‘1970-01-01’:当前所在行数取不够前面的行,取默认行(比如取前5行,但是当前行数是第四行,就取值为(‘1970-01-01’)的所在行
-
-
lead :
同上
语法如下:
举例:
-
现在要获取当前订单的上一个订单的时间跟下一个订单的时间(统计一下时间间隔)
-
可以看到,lag根据order_date做一个跨行,先按照时间排序(over order by )后
first_value和last_value:
语法:
- first_value(字段3,FALSE) 字段3表示具体取哪个字段的值,false表示允许null的值作为结果,如果窗口内某一行是null值,结果就是null
dense_rank() 如果相同的值,给一样的名次
row_number() 如果相同的值,按照插入表的顺序分名次
1)表结构
2)建表语句
1)统计每个用户截至每次下单的累积下单总额
期望结果:
(2)需求实现
2)统计每个用户截至每次下单的当月累积下单总额
(1)期望结果
(2)需求实现
3)统计每个用户每次下单距离上次下单相隔的天数(首次下单按0天算)
(1)期望结果
(2)需求实现
4)查询所有下单记录以及每个用户的每个下单记录所在月份的首末次下单日期
(1)期望结果
(2)需求实现
5)为每个用户的所有下单记录按照订单金额进行排名
(1)期望结果
(2)需求实现