窗口函数到底有多「神奇」?

2021-01-25 12:12:20 浏览数 (2)

实习和秋招笔面试的时候,SQL的考察必不可少,除了题目中会涉及业务背景外,大同小异的,大都考察聚合、表连接、窗口函数,尤以各种各样的窗口函数为重。

可不要再傻乎乎的问我,MySQL没有窗口函数啊,我怎么从没有看到过?在哪里能学到呢?盆友!清醒一点!多接触点其他的DBMS吧!几乎处处可见窗口函数,而且会频繁考察。

MySQL升级到8.0以上就能拥有此功能了,一般的窗口函数都能用,但是狗血的是我不能在上面试验grouping sets,只能在hive上写的时候才能“大展拳脚”,夸张了,hhhh,那么一起来看几道与窗口函数相关的题目吧。

题目一

表mall_rate中记录了不同商户的费率变化信息,要求按照时间轴顺序,取出费率发生了状态变化的数据行。表及相关数据如下:

解题思路:

lag或lead函数可以将上一行或下一行的字段内容获取到本行,这样便可以进行某些字段是否发生变化的比较,从而进行状态是否变化的比较,有些题目中会出现一些如“连续记录”,“沿时间轴”,“查询**上次记录的时间”,“查询**前n次记录的时间”等字眼,这些关键字预示着可能会需要用到lag或lead函数去获取上n行或下n行字段的内容到本行,进行数据选取或比较。

法1:

查询结果如下:

法2:

查询结果如下:

知识点归纳:

LAG(col,n,default)用于统计窗口内往上第n行值,第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上第n行为null时,取默认值,如不指定,则为null)

LEAD(col,n,default)与LAG相反,用于统计窗口内往下第n行值,第一个参数为列名,第二个参数为往下第n行(可选,默认为1),第三个参数为默认值(当往下第n行为null时,取默认值,如不指定,则为null)

与LAG和LEAD同时作为知识点出现的,还有FIRST_VALUE和LAST_VALUE。

FIRST_VALUE(字段),取分组内排序后,截止到当前行的第一个值

LAST_VALUE(字段),取分组内排序后,截止到当前行的最后一个值

安排一道练习题吧~

表tmp中包括用户及其访问的场景及对应访问时间,求取用户id对应的前两个不同的场景(如果场景重复,选访问时间在前的场景,访问场景数不足两个时,输出到不足两个的输出即可),输出示例如下:

题目二

某商店有如下一张用户订单表order_table,其中记录了用户名,订单时间及订单金额,以此表为例,可以提出多个用窗口函数解决的小问题。相关数据如下:

(1)查询本店2017年1月份有购买行为的顾客姓名及购买次数。

解题思路:

可以采用一般的聚合函数count(),也可以使用窗口函数count() over();对于日期的限制可采用各种方式,如日期转换函数,也可以使用substr()。

法1:

法2:

(2)查询顾客的购买明细及每个月所有顾客的购买总额。

解题思路:

由于需要每位顾客明细后都要带一个当月所有顾客购买总额的字段,因此可以选择使用窗口函数中的sum() over()获得这个字段。

除此之外,也可以使用sum() over()做很多其他场景的操作,比如:

也可以使用先前介绍的lag或lead去求取顾客的上一次购买时间:

(3)查询整个订单信息中前20%时间的订单信息。

解题思路:

排序,取前20%。以前我有过一种操作是先使用窗口函数中的row_number()进行排序,搞一个rank,然后取最大rank的20%作为限制条件,取到前20%。后来发现别人都有顶好用的ntile,我真的是!!!

解法如下:

分桶(分组排序),按照你的意愿进行设置,分为几个桶,比如5个,每个桶占20%的记录,每个桶会有编号,取出想取的编号对应的数据即可。

其他各种各样有趣和有用的函数还有一箩筐,但是个人接触的也有限,正在慢慢学习中,以前分享的row_number,rank,dense_rank不知道你们还记不记得了,划重点呀!

0 人点赞