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. Java模拟UDP通信

    目录 Java基础:模拟UDP通信 1.一次发送,一次接收 1.1.发送方 1.2.接收方 2.多次发送,多次接收 2.1.发送方 2.2.接收方 3.模拟双方通信 3.1.发送方的线程 3.2.接收 ...

  2. mac下xampp使用phpmyadmin搭建后台

    情景 使用xampp搭建一个后端环境,前提已经有后端和数据库配置文件 安装和启动xampp 安装xampp没什么可说的,在https://www.apachefriends.org/index.htm ...

  3. 04_CSS入门和高级技巧(2)

    上节课复习 HTML表格,table.tr.td(th):thead.tbody:caption. 一定要会根据图形,来写表格: <table border="1"> ...

  4. 【Linux基础总结】Shell 基础编程

    Shell 基础编程 重启虚拟机遇到磁盘损坏如何解决 Shell编程中变量的声明.引用及作用域 Shell程序 概述 以文件形式存放批量的Linux命令集合,该文件能够被Shell解释执行,这种文件就 ...

  5. 一文教你快速搞懂速度曲线规划之T形曲线(超详细+图文+推导+附件代码)

    运动控制中常用的T速度曲线规划的原理和程序实现,最后给出了测试结果: 如果本文帮到了您,请帮忙点个赞

  6. fork...join的用法

    如果希望在仿真的某一时刻同时启动多个任务,可以使用fork....join语句.例如,在仿真开始的 100 ns 后,希望同时启动发送和接收任务,而不是发送完毕后再进行接收,如下所示: initial ...

  7. VMware Centos7 NAT 无法上网的解决方法

    问题描述: VMware下CentOS7使用NAT上网方式无法连网 解决方案: 网络设置为DHCP自动获取IP 查看主机(不是虚拟机)的相关服务是否打开,主要是VMware DHCP 和VMware ...

  8. python100例 21-30

    021 猴子吃桃 题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到第10天早 ...

  9. 手机网页,div内滚动条,以及div内部滚动条拉到底部之后触发事件

    var gao = document.documentElement.clientHeight; var headHeight = parseInt($('.yhead').css('height') ...

  10. 小姐姐教你定制一个Logstash Java Filter

    Logstash是用来收集数据,解析处理数据,最终输出数据到存储组件的处理引擎.数据处理流程为: Logstash Java Filter 就是基于Logstash的Filter扩展API开发一个用J ...