why window function
窗口函数可以根据over()后的子句使用函数,可以理解为over会给每个要计算的栏开一口,定义作用范围,对查询的结果多出一列,这一列可以是聚合值,也可以是排序值。比起group by更灵活,当需要根据不同分区进行计算时,分析函数即可使用。
语法
over后面写要作用的范围,格式如下:
(ROWS | RANGE) BETWEEN (UNBOUNDED | [num]) PRECEDING AND ([num] PRECEDING | CURRENT ROW | (UNBOUNDED | [num]) FOLLOWING)
(ROWS | RANGE) BETWEEN CURRENT ROW AND (CURRENT ROW | (UNBOUNDED | [num]) FOLLOWING)
(ROWS | RANGE) BETWEEN [num] FOLLOWING AND (UNBOUNDED | [num]) FOLLOWING
若不写的话预设为整个范围。即:rows between unbounded preceding and unbounded following
通常会根据排序计算,因此会在后方加入排序函数。如
果over()子句中接order by,例如:over(order by date),
则默认的开窗范围为根据date排序后的第一行到当前行,rows between unbounded preceding and current row。
在窗口函数中使用分组的结果来分析,使用partition by + order by
例:
--统计每天u_id的vv大盘占比
select u_id, p_date, vv, vv/sum(vv) over(partition by p_date)
from table
例:取前20%头部视频使用NTILE分析函数,把所有vv分为5份,为1的哪一份就是我们想要的结果.
--取前20%头部视频
select id, p_date, vv
,ntile(5) over(partition by p_date order by vv deac) as top20
from photo_table;
select id, p_date, sum(vv)
,ntile(5) over(order by sum(vv) deac) as top20
from photo_table
group by id, p_date;
例:计算累计和
根据月份排序,给出每个月份的视频观看数以及累计到当月的视频观看数。
select id, month, sum(vv)
,sum(sum(vv)) over(order by month) as acumulative_vv--这里共聚合了两次
from photo_table
group by month
order by month;
附录
有些地方在子句当中使用分组时会用distribute by,我个人理解与partition by其实无本质上的区别,只是要注意搭配的排序函数。
patition by是按照一个一个reduce去处理数据的,所以要使用全局排序order by
而distribute by是按照多个reduce去处理数据的,所以对应的排序是局部排序sort by
另外,我还看到有其他同学遇到更负责的情况,如在要求同一个客户下,取卡审核日期小的卡,若卡审核日期相同,取卡申请id小的卡,若卡申请id相同,则取卡种和卡申请时卡种相同的卡。
这时候在条件里要写:
select *
from (
select row_number() over(partition by id order by create_date, apply_id, case when produce=cardtype then '1'end ) as rk
from custom_tb
)tb1
where tb1.rk=1