(求TopN)求出每种爱好中,年龄最大的两个人(姓名,爱好,年龄)
四个字段的意思:
id,姓名,年龄,爱好
表名topn
字段id, name, age, favors
1,ngxiaoming,45,a-c-d-f
2,huangzitao,36,b-c-d-e
3,huanglei,41,c-d-e
4,liushishi,22,a-d-e
5,liudehua,39,e-f-d
6,liuyifei,35,a-d-e
用到关键技术:
虚拟视图leteral view、explode、窗口函数row_number()
-
需要把favor字段进行拆分,拆成多行一列的值
比如6,liuyifei,35,a-d-e拆成:
6,liuyifei,35,a
6,liuyifei,35,d
6,liuyifei,35,e -
使用explode进行拆分
select explode(split("a-d-e","-"));
无法直接写sql语句进行favors的拆分,所以需要借助虚拟视图
-
借助虚拟视图使用CTAS创建一张topn1表
语法:lateral view utdf(表达式) 虚拟表名 as 虚拟表的列名,生成一张虚拟表。utdf函数通常把explode和split结合使用,针对from的表(如这里是topn表)的每一行进行操作。create table topn1 as select id,name,age,favortable.favor from topn lateral view explode(split(favors,"-")) favortable as favor;
-
求出每种爱好的年龄最大的前2名
分析:(一般既要分组又要排序,就要想到窗口函数)
给topn1表弄一个排名,按爱好进行降序排序,然后选取每种爱好的前2名即可。窗口函数 row_number() 排序,排名相同编号也往后顺位
select name,favor,age, row_number() over(partition by favor order by age desc) as index from topn1;
-
求排名前2个记录
因为where的执行顺序要先于窗口函数,无法直接使用条件index<=2。必须在外面再套一层select。select c.name,c.favor,c.age from ( select name,favor,age,row_number() over(partition by favor order by age desc) as index from topn1) as c where c.index <=2;
窗口函数-排序-区别row_number() 排序,排名相同编号也往后顺位
rank() 排序,排名相同编号一样,跳过空位,比如4后直接到6
dense_rank() 排序,排名相同编号一样,不跳过空位,比如4后接着到5
当排名一样的时候,选排名前2,可能是2个人,也可能3个人,所以需要按实际需求选择用哪个排序函数。