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导出excel文件,第二步先实现自写二维数组加入模板excel文件后导出

    今天主要研究数据加入EXCEL并导出的问题,先不从数据库提取数据导出,自己先写一个二维数组,然后遍历二维数组写入excel模板中导出,首先根据模板excel的内容书写对应的二维数组 $arr=arra ...

  2. linux centos7搭建redis-5.0.5

    1. 下载redis 1.1 下载地址 http://download.redis.io/releases/ 1.2 安装版本 redis-5.0.5.tar.gz 2. 安装redis 2.1 前置 ...

  3. Viterbi-Algorithm(维特比)算法

    CSDN博客:皮乾东  知乎:Htrying  微博:Htring的微博  微信公众号:自然语言处理爱好者(ID:NLP_lover)  文章来自:<数学之美> Viterbi-Algor ...

  4. python之邮件发送自动化

    # -*- coding:utf-8 -*-#@Time : 2020/3/24 22:55#@Autor: Mr.White#@File : 发送邮件.py 一.导入所需要的类 import smt ...

  5. CF-448C Painting Fence 分治

    Painting fence 题意 乍一看以为是之前做过的一道单调队列优化的DP,不是. 也是有n块木板,每个木板宽1米,有一个高度ai,现在要把他们刷成橘色,给了你一个宽一米的刷子,你可以横着刷,或 ...

  6. 画结构图的神器 Graphviz

    经常看到别人的论文里各种优美的图,没想过它们是怎么来的,前两天也是在看论文的时候被推荐了一款画图软件graphviz,稍微了解了一下这个画图软件,据说是贝尔实验室的几位牛人开发出来的,试了一下觉得很不 ...

  7. IDC预测2020云服务逆势增长!云服务器已成上云首选

    IDC预测2020云服务逆势增长!云服务器已成上云首选 据IDC最新预测指出,2020年IT基础设施支出今年将增长约4%,达到2370亿美元,驱动力主要来源于云服务. 受疫情的影响,不少企业开源节流, ...

  8. 关于tez-ui的"All DAGs"和"Hive Queries"页面信息为空的问题解决过程

    近段时间发现公司的HDP大数据平台的tez-ui页面不能用了,页面显示为空,导致通过hive提交的sql不能方便地查找到Yarn上对应的applicationId,只能通过beeline的屏幕输出信息 ...

  9. Atcoder Beginner Contest 166

    VP赛况如下: 前言:感觉这一场题目难度还是比较贴近新生的,我一个codeforces小蓝名一小时居然AK了,F题数据有点水(?)暴力dfs居然都能过... A:A?C 题意:给你字符串,如果字符串是 ...

  10. spark机器学习从0到1特征选择-卡方选择器(十五)

      一.公式 卡方检验的基本公式,也就是χ2的计算公式,即观察值和理论值之间的偏差   卡方检验公式 其中:A 为观察值,E为理论值,k为观察值的个数,最后一个式子实际上就是具体计算的方法了 n 为总 ...