Hive SQL练习之成绩分析

数据:[id, 学号,班级,科目,成绩]
1,1,1,yuwen,80
2,1,1,shuxue,85
3,2,1,yuwen,75
4,2,1,shuxue,70
5,3,1,yuwen,86
6,3,1,shuxue,72
7,4,2,yuwen,88
8,4,2,shuxue,99
9,5,2,yuwen,86
10,5,2,shuxue,94
11,6,2,yuwen,56
12,6,2,shuxue,96

题目:

(1)求每个班级前三名的同学(组内topN问题);

分析:按班级分组,同时取每个同学的平均成绩(或总分)还需要对学生分组。

1)按班级+学生分组,取每个同学平均成绩

select cid, sid, avg(score) avg_score from t_course group by cid, sid order by cid, avg_score desc;
+------+------+------------+
| cid | sid | avg_score |
+------+------+------------+
| 1 | 1 | 82.5 |
| 1 | 3 | 79.0 |
| 1 | 2 | 72.5 |
| 2 | 4 | 93.5 |
| 2 | 5 | 90.0 |
| 2 | 6 | 76.0 |
+------+------+------------+ 注意,这里因为数据量太少(每个班就三名同学),直接按上面排序就取出了前三名学生。
这个题实际考察的是多分组(班级+学生),组内TopN(成绩前三名),应该使用dense_rank函数。
- 请自行回顾row_number、rank、dense_rank三个函数的区别。 例如取前两名,就得用上dense_rank
select * from (select cid, sid, avg(score) as avg_score, dense_rank() over (partition by cid order by avg(score) desc) as rank from t_course group by cid, sid order by cid) t where rank<=2;
+--------+--------+--------------+---------+
| t.cid | t.sid | t.avg_score | t.rank |
+--------+--------+--------------+---------+
| 1 | 1 | 82.5 | 1 |
| 1 | 3 | 79.0 | 2 |
| 2 | 4 | 93.5 | 1 |
| 2 | 5 | 90.0 | 2 |
+--------+--------+--------------+---------+

(2)求语文成绩比数学成绩高的同学,要求使用两种方式完成。

提示:case when,collect_set,concat,concat_set

本人自创方法(也是最简单的方法)

0: jdbc:hive2://bigboss3:10000> select * from(select id,sid,cid,score,lead(score) over() as shuxue from t_course)t where id%2=1 and score>shuxue;
+-------+--------+--------+----------+-----------+
| t.id | t.sid | t.cid | t.score | t.shuxue |
+-------+--------+--------+----------+-----------+
| 3 | 2 | 1 | 75 | 70 |
| 5 | 3 | 1 | 86 | 72 |
+-------+--------+--------+----------+-----------+

解析:每个学生都是相邻行科目与成绩不同,使用lead(score) over()把成绩那一列整体向上提升一行,那么奇数行就有该同学语文和数学成绩,这样比起来不就很简单了吗,这个方法最简单了,也是我自己想的,得出答案也是正确的。

方法二:使用collect_set,concat,concat_set,str_to_map

collect_set函数将多行转换为一行,使用concat,concat_set,可以将字段拼接为map格式

0: jdbc:hive2://bigboss3:10000> select * from (select sid,cid,str_to_map(concat_ws(",",collect_set(sc))) as scmap from (select sid,cid,concat(course,":",score) as sc from t_course) t group by sid,cid)s where s.scmap["yuwen"]>s.scmap["shuxue"];
+--------+--------+-------------------------------+
| s.sid | s.cid | s.scmap |
+--------+--------+-------------------------------+
| 3 | 1 | {"yuwen":"86","shuxue":"72"} |
| 2 | 1 | {"yuwen":"75","shuxue":"70"} |
+--------+--------+-------------------------------+
2 rows selected (1.369 seconds)

解析:

1)使用concat方法,将学科和成绩进行拼接
select sid, concat(course, ":", score) from t_course;
+------+------------+
| sid | _c1 |
+------+------------+
| 1 | yuwen:80 |
| 1 | shuxue:85 |
| 2 | yuwen:75 |
| 2 | shuxue:70 | 2)使用collect_set函数,每个同学的多行成绩合并到一行
注意:多行变一行是聚集操作,需要分组
select sid, collect_set(concat(course, ":", score)) from t_course group by sid;
+------+---------------------------+
| sid | _c1 |
+------+---------------------------+
| 4 | ["yuwen:88","shuxue:99"] |
| 6 | ["yuwen:56","shuxue:96"] |
| 2 | ["yuwen:75","shuxue:70"] |
| 1 | ["yuwen:80","shuxue:85"] |
| 3 | ["yuwen:86","shuxue:72"] |
| 5 | ["yuwen:86","shuxue:94"] |
+------+---------------------------+ 3)转换为map格式,方便获取成绩
注意:上面获取的["yuwen:88","shuxue:99"]是数组,无法直接转换为map,需要先使用concat_ws将数组转换为字符串
select sid, concat_ws(",", collect_set(concat(course, ":", score))) from t_course group by sid;
+------+---------------------+
| sid | _c1 |
+------+---------------------+
| 4 | yuwen:88,shuxue:99 |
| 6 | yuwen:56,shuxue:96 |
| 2 | yuwen:75,shuxue:70 | 再将字符串转换为map
select sid, str_to_map(concat_ws(",", collect_set(concat(course, ":", score)))) as score_map from t_course group by sid;
+------+-------------------------------+
| sid | score_map |
+------+-------------------------------+
| 4 | {"yuwen":"88","shuxue":"99"} |
| 6 | {"yuwen":"56","shuxue":"96"} |
| 2 | {"yuwen":"75","shuxue":"70"} |
| 1 | {"yuwen":"80","shuxue":"85"} |
| 3 | {"yuwen":"86","shuxue":"72"} |
| 5 | {"yuwen":"86","shuxue":"94"} |
+------+-------------------------------+ 4)通过map访问学科和成绩,并进行过滤
select sid, score_map["yuwen"] as yuwen, score_map["shuxue"] as shuxue from (select sid, str_to_map(concat_ws(",", collect_set(concat(course, ":", score)))) as score_map from t_course group by sid) t where score_map["yuwen"]>score_map["shuxue"];
+------+--------+---------+
| sid | yuwen | shuxue |
+------+--------+---------+
| 2 | 75 | 70 |
| 3 | 86 | 72 |
+------+--------+---------+

方法三:case when

这个方法比较巧妙,一般想不出来

select sid, max(yuwen) as score_yw, max(shuxue) as score_sx from (select *, case course when "yuwen" then score else 0 end as yuwen, case course when "shuxue" then score else 0 end as shuxue from t_course) t group by sid  having score_yw>score_sx;
+------+-----------+-----------+
| sid | score_yw | score_sx |
+------+-----------+-----------+
| 2 | 75 | 70 |
| 3 | 86 | 72 |
+------+-----------+-----------+

解析

思路:由于各科成绩在不同行,无法直接进行比较,可以使用case  when新增yuwen、shuxue两列,然后再将各科成绩转换为一行进行比较。
1)新增yuwen、shuxue两列
select *, case course when "yuwen" then score else 0 end as yuwen, case course when "shuxue" then score else 0 end as shuxue from t_course;
+--------------+---------------+---------------+------------------+-----------------+--------+---------+
| t_course.id | t_course.sid | t_course.cid | t_course.course | t_course.score | yuwen | shuxue |
+--------------+---------------+---------------+------------------+-----------------+--------+---------+
| 1 | 1 | 1 | yuwen | 80 | 80 | 0 |
| 2 | 1 | 1 | shuxue | 85 | 0 | 85 |
| 3 | 2 | 1 | yuwen | 75 | 75 | 0 |
| 4 | 2 | 1 | shuxue | 70 | 0 | 70 |
| 5 | 3 | 1 | yuwen | 86 | 86 | 0 |
| 6 | 3 | 1 | shuxue | 72 | 0 | 72 |
| 7 | 4 | 2 | yuwen | 88 | 88 | 0 |
| 8 | 4 | 2 | shuxue | 99 | 0 | 99 |
| 9 | 5 | 2 | yuwen | 86 | 86 | 0 |
| 10 | 5 | 2 | shuxue | 94 | 0 | 94 |
| 11 | 6 | 2 | yuwen | 56 | 56 | 0 |
| 12 | 6 | 2 | shuxue | 96 | 0 | 96 |
+--------------+---------------+---------------+------------------+-----------------+--------+---------+ case course when "yuwen" then score else 0 end as yuwen解析:
对每一行,当course取值为"yuwen"时,则新增的yuwen字段值为score(语文成绩),否则(course值为shuxue),取值为0; 2)对每一个学生做分组,目的是将每个学生的成绩显示到一行
select sid, max(yuwen) as score_yw, max(shuxue) as score_sx from (select *, case course when "yuwen" then score else 0 end as yuwen, case course when "shuxue" then score else 0 end as shuxue from t_course) t group by sid order by sid;
+------+-----------+-----------+
| sid | score_yw | score_sx |
+------+-----------+-----------+
| 1 | 80 | 85 |
| 2 | 75 | 70 |
| 3 | 86 | 72 |
| 4 | 88 | 99 |
| 5 | 86 | 94 |
| 6 | 56 | 96 |
+------+-----------+-----------+ 3)查找语文成绩更高的学生,注意分组条件过滤使用having,而不是where
select sid, max(yuwen) as score_yw, max(shuxue) as score_sx from (select *, case course when "yuwen" then score else 0 end as yuwen, case course when "shuxue" then score else 0 end as shuxue from t_course) t group by sid having score_yw>score_sx;
+------+-----------+-----------+
| sid | score_yw | score_sx |
+------+-----------+-----------+
| 2 | 75 | 70 |
| 3 | 86 | 72 |
+------+-----------+-----------+

【HIVE高级笔试必备题型】(组内topN、相邻行的值比较问题)求语文大于数学_/_求文科大于理科成绩的学生的更多相关文章

  1. 大数据技术之_08_Hive学习_04_压缩和存储(Hive高级)+ 企业级调优(Hive优化)

    第8章 压缩和存储(Hive高级)8.1 Hadoop源码编译支持Snappy压缩8.1.1 资源准备8.1.2 jar包安装8.1.3 编译源码8.2 Hadoop压缩配置8.2.1 MR支持的压缩 ...

  2. ROWNUMBER() OVER( PARTITION BY COL1 ORDER BY COL2)用法,先分组,然后在组内排名,分组计算,主表与附表一对多取唯一等

    ROWNUMBER() OVER( PARTITION BY COL1 ORDER BY COL2)用法 今天在使用多字段去重时,由于某些字段有多种可能性,只需根据部分字段进行去重,在网上看到了row ...

  3. 组内Linq培训记录

    注: 由于该培训是在组内分享,先写成了Word,而word中的代码都以截图方式呈现了,而在博客园不能很方便的粘贴截图进来,所以我用插入代码的方式加进来,如果文中说“如下图”或“如下图代码”,那么就直接 ...

  4. sql 分组后 组内排名

    语法:ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN) 简单的说row_number()从1开始,为每一条分组记录返回一个数字,这里的ROW ...

  5. sql查询技巧,按时间分段进行分组,每半小时一组统计组内记录数量

    今天拿到一个查询需求,需要统计某一天各个时间段内的记录数量. 具体是统计某天9:00至22:00时间段,每半小时内订单的数量,最后形成的数据形式如下: 时间段          订单数 9:00~9: ...

  6. 如何用SQL实现组内前几名的输出

    关于问题 如何查询组内最大的,最小的,大家或许都知道,无非是min.max的函数使用.可是如何在MySQL中查找组内最好的前两个,或者前三个? 什么是相关子查询 在提出对于这个问题的对应方法之前,首先 ...

  7. BIRT实现组内跨行计算

    问题来源:http://developer.actuate.com/community/forum/index.php?/topic/36160-dealing-with-previous-rows- ...

  8. 模拟QQ分组(具有伸缩功能) (添加开源框架的光闪烁效果)SimpleExpandableListAdapter 适配器的用法,并且可添加组及其组内数据。

    package com.lixu.qqfenzu; import java.util.ArrayList; import java.util.HashMap; import java.util.Lis ...

  9. sql server迁移数据(文件组之间的互相迁移与 文件组内文件的互相迁移)

    转自:https://www.cnblogs.com/lyhabc/p/3504380.html?utm_source=tuicool SQLSERVER将数据移到另一个文件组之后清空文件组并删除文件 ...

随机推荐

  1. php时间输出结果减去一分钟

    如: <?=date("m-d H:i",strtotime($rs["kgtime"]));?> 假设结果是09-03-23:30,如何让它变成0 ...

  2. C# 基础至集合-数组、List<T>、ArrayList、LinkedList、HashMap的一些区别

    1:数组 ]; //赋值 strs[] = "; strs[] = "; //修改 strs[] = "burg"; //删除 没法删除 除非转化为可变数组li ...

  3. JavaScript 的核心机制——event loop(最易懂版)

    前言 javascript从诞生之日起就是一门单线程的非阻塞的脚本语言. 非阻塞就是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如ajax事件)时,主线程会挂起(pen ...

  4. 用python爬了厦门人才网的.net岗位

    为了看看.net的就业行情怎么样,用python爬取了厦门人才网.net岗位的信息,话不多说上代码,python没学多久,如果有什么不妥请指正 import requests from bs4 imp ...

  5. python解析excel中图片+提取图片

    解析表格是常用的技术.但是有些表各里面有图片怎么办?我想获得表格里面的图片,值得注意的是,图片没有位置信息,所以最好给图片进行编号,编号代表位置. 下面附上提取表格里面图片的代码.只要输出表格地址,和 ...

  6. 不会看 Explain执行计划,劝你简历别写熟悉 SQL优化

    昨天中午在食堂,和部门的技术大牛们坐在一桌吃饭,作为一个卑微技术渣仔默默的吃着饭,听大佬们高谈阔论,研究各种高端技术,我TM也想说话可实在插不上嘴. 聊着聊着突然说到他上午面试了一个工作6年的程序员, ...

  7. 你想了解的python基础数据类型这里都有

    目录 python基础数据总结 数字型数据类型 数字型数据基本知识 算术运算符 进制 二进制运算符 字符串数据类型 字符串基础知识 字符串数据操作方法(增 查 改) 集合数据类型 集合基础知识 集合元 ...

  8. Gym101635K Blowing Candles

    题目链接:http://codeforces.com/gym/101635 题目大意: 推荐一篇文章:https://blog.csdn.net/wang_heng199/article/detail ...

  9. LoadBalancer在kubernetes架构下的实践

    Backgound 借助于kubernetes优秀的弹性扩缩功能,运行其中的应用程序能够在流量突增的时候坦然应对,在流量低谷的时候无需担心成本.但于此同时,也带来了极大的挑战: 弹性扩缩导致容器IP动 ...

  10. Mac打不开inkscape怎么办

    本经验题目提到的是一款矢量图片编辑软件,对于打开不开的软件,完全可以通过卸载软件后进行安装.这里就从安装以及卸载的过程说明一下这个软件的安装卸载过程. 方法/步骤 打开电脑任意一个浏览器图标,进入浏览 ...