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. 王颖奇 20171010129《面向对象程序设计(java)》第十二周学习总结

    实验十二  图形程序设计 理论: 10.1 AWT与Swing简介 10.2 框架的创建10.3 图形程序设计10.4 显示图像 (具体学习总结在最后) 实验: 实验时间 2018-11-14 1.实 ...

  2. 老板:kill -9 的原理都不知道就敢去线上执行?明天不用来了!

    GitHub 14.5k Star 的Java工程师成神之路,开放阅读了! 相信很多程序员对于Linux系统都不陌生,即使自己的日常开发机器不是Linux,那么线上服务器也大部分都是的,所以,掌握常用 ...

  3. C# 数据操作系列 - 5. EF Core 入门

    0.前言 上一章简单介绍了一下ORM框架,并手写了一个类似ORM的工具类.这一章将介绍一个在C#世界里大名鼎鼎的ORM框架--Entity Framework的Core版. Entity Framew ...

  4. 安装Kibana出现的问题

    安装Kibana出现的问题 前言 该问题的出现是在安装配置完成之后,也就是说下载好了kibana的相关包,在启动过程中出现的错误,该错误是在centos6的机器上引发的,是因为系统中的GLIBC_2. ...

  5. curl发送请求

    一.get请求 curl "http://www.baidu.com"  如果这里的URL指向的是一个文件或者一幅图都可以直接下载到本地 curl -i "http:// ...

  6. Codeforces 1272E (Nearest Opposite Parity,反向建边)

    题意:给你n个数,每个数的值为a[i],每个点可以从i这号点跳转至(i - a[i]) 或 (i + a[i])点,点的范围为[1,n],然后问的是从偶数点跳至奇数点,从奇数点跳至偶数点的最少次数是多 ...

  7. .Net Core3.0 WebApi 项目框架搭建 五: 轻量型ORM+异步泛型仓储

    .Net Core3.0 WebApi 项目框架搭建:目录 SqlSugar介绍 SqlSugar是国人开发者开发的一款基于.NET的ORM框架,是可以运行在.NET 4.+ & .NET C ...

  8. webpack4多页应用HTML按需添加入口依赖chunk【html-webpack-plugin & html-inline-entry-chunk-plugin】

    在webpack4中使用splitChunkPlugin时,根据需要将公共代码拆分为多个依赖后,需要在创建htmlWebpackPlugin时候按需引入对应入口文件依赖的chunk.但是html-we ...

  9. [翻译] .NET 官宣跨平台 UI 框架 MAUI

    MAUI Build 2020 大会上,微软终于正式公布 .NET 上的跨平台框架,正式版将在 .NET 6 和大家见面. MAUI 是日益流行的 Xamarin.Forms 的进化,Xamarin. ...

  10. 【雕爷学编程】Arduino动手做(6)---声音传感器模块

    37款传感器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器,依照实践(动手试试)出真知的理念,以学习和交流为目的,这里准备逐一做做实验 ...