sql分组排序取top n

数据库查询*分组排序取top n

要求:按照课程分组,查找每个课程最高的两个成绩。

数据文件如下:

第一列no为学号,第二列course为课程,第三列score为分数

mysql> select * from lesson;
+-------+---------+-------+
| no    | course  | score |
+-------+---------+-------+
| N0101 | Marth   |   100 |
| N0102 | English |    12 |
| N0102 | Chinese |    55 |
| N0102 | History |    58 |
| N0102 | Marth   |    25 |
| N0103 | English |   100 |
| N0103 | Chinese |    87 |
| N0103 | History |    88 |
| N0103 | Marth   |    72 |
| N0104 | English |    20 |
| N0104 | Chinese |    60 |
| N0104 | History |    88 |
| N0104 | Marth   |    56 |
| N0105 | English |    56 |
| N0105 | Chinese |    88 |
| N0105 | History |    88 |
| N0201 | English |    66 |
| N0201 | Chinese |    77 |
| N0201 | History |    80 |
| N0201 | Marth   |   100 |
| N0202 | English |    35 |
| N0202 | Chinese |    56 |
| N0202 | History |    86 |
| N0202 | Marth   |    99 |
| N0203 | English |   100 |
| N0203 | Chinese |    87 |
| N0203 | History |    88 |
| N0203 | Marth   |    57 |
| N0204 | English |    98 |
| N0204 | Chinese |   100 |
| N0204 | History |    66 |
| N0204 | Marth   |    71 |
| N0205 | English |    98 |
| N0205 | Chinese |   100 |
| N0205 | History |    66 |
| N0205 | Marth   |    71 |
| N0301 | English |    66 |
| N0301 | Chinese |    89 |
| N0301 | History |    68 |
| N0301 | Marth   |    83 |
| N0302 | English |    76 |
| N0302 | Chinese |    99 |
| N0302 | History |    80 |
| N0302 | Marth   |    74 |
| N0303 | English |   100 |
| N0303 | Chinese |   100 |
| N0303 | History |    88 |
| N0303 | Marth   |    57 |
| N0304 | English |    76 |
| N0304 | Chinese |   100 |
| N0304 | History |    66 |
| N0304 | Marth   |    86 |
| N0305 | English |    98 |
| N0305 | Chinese |   100 |
| N0305 | History |    40 |
| N0305 | Marth   |    59 |
| N0306 | English |    52 |
| N0306 | Chinese |    87 |
| N0306 | History |    72 |
| N0306 | Marth   |    71 |
| N0101 | Chinese |    55 |
| N0101 | History |    84 |
| N0101 | English |    82 |
| N0101 | English |    82 |
+-------+---------+-------+
64 rows in set

在hive上查询

select a.course,a.score
from
(
select course,score,row_number() over(partition by course order by score desc) as n
from lesson
)a
where a.n<=2; 


其中:

row_number() over(partition by course order by score desc)
意思是以课程分组,按成绩递减排序,并为每组中的数据打上行号的标记,从1开始。

这样,再在外层套一层过滤行号小于等于2的即可:-D

查询结果如下图1所示:


图1 hive查询结果

在mysql上查询

由于mysql不支持row_number()over()等窗口函数

所以/(ㄒoㄒ)/~~

方法1.自查询比较

select course,score
from lesson a
where 2 >
(
select count(1)
from lesson b
where a.score<b.score and a.course=b.course
)
order by a.course,a.score desc;

因为是查询最高的两个成绩,所以是2>,如果查询最高的前N个成绩,改成 N>

该条sql语句的大概思路是:

从a表中拿出一条数据,与b表中所有与该条数据相同course的数据比较,统计出b表有多少相同课程的score比该条数据的score高;

如果b表中有0条比该条数据高,则该条数据是该门课程的最高分;

如果统计出有1条数据,则该条数据是该门课程分数的第二高;


但是,还存在一些问题:

比如,最高分存在多个,则会统计出多于2条的数据,如下图2统计结果也有所反应:



图2 mysql查询结果


方法2.动态sql

SET @row=0;
SET @groupid='';
select a.course,a.score
from
(
select no,course,score,case when @groupid=course then @row:=@row+1 else @row:=1 end rownum,@groupid:=course from lesson
order by course,score desc
)a
where a.rownum<=2;

其中:
@row用于统计行号,@groupid用于分组,记录该组的名称
select no,course,score,case when @groupid=course then @row:=@row+1 else @row:=1 end rownum,@groupid:=course from lesson
order by course,score desc

意思是:按照分组名course和需要的排序score递增 进行排序,这样,相同课程就会排在一起,且相同的课程之间按照成绩排序。
取出一条数据,如果该条数据的course与@group相同,则意味着是相同课程之间的比较,那么@row自加1。
否则意味着该条数据是另一门课程的第一条数据,则@row=1


这样每个课程就能够按照成绩排序并标记上行号
那么外层只需要过滤rownum<=2即可得到每门课的前2个最高分。
最后执行结果与hive一致,不再上图片了。






  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: Spark RDD中分组TopN案例是指在一个RDD中,根据某个键值进行分组,然后对每个组内的数据进行排序出每个组内的前N个数据。这种操作在数据分析和处理中非常常见,可以用于统计每个地区的销售额排名前N的产品、每个用户的消费排名前N的商品等。 优化方面,可以考虑使用Spark SQL或DataFrame来实现分组TopN操作,因为它们提供了更高级的API和优化技术,可以更快速地处理大规模数据。另外,可以使用分布式缓存技术将数据缓存到内存中,以加快数据访问速度。还可以使用分区和并行计算等技术来提高计算效率。 ### 回答2: Spark RDD中分组Top N的案例可以是对一个大数据集中的用户数据进行分组,然后每个组中消费金额最高的前N个用户。这个案例可以通过以下步骤来实现: 1. 将用户数据载入Spark RDD中,每个数据记录包含用户ID和消费金额。 2. 使用groupBy函数将RDD按照用户ID进行分组,得到一个以用户ID为key,包含相同用户ID的数据记录的value的RDD。 3. 对每个分组的value调用top函数,指定N的值,以获每个分组中消费金额最高的前N个用户。 4. 可以将每个分组中Top N的用户使用flatMap函数展开为多个记录,并可以添加一个新的字段表示该记录属于哪个分组。 5. 最后,可以使用collect函数将结果转化为数组或者保存到文件或数据库中。 在这个案例中,进行优化的关键是减少数据的传输和处理开销。可以使用缓存或持久化函数对RDD进行优化,以减少重复计算。另外,可以使用并行操作来加速计算,如使用并行的排序算法,或向集群中的多个节点分发计算任务。 对于分组Top N的优化,还可以考虑使用局部聚合和全局聚合的策略。首先对每个分组内的数据进行局部聚合,例如计算每个分组的前M个最大值。然后,对所有分组的局部聚合结果进行全局聚合,例如计算所有分组的前K个最大值。 另一个优化策略是使用采样技术,例如随机采样或分层采样,以减少需要处理的数据量。 最后,还可以考虑使用Spark的其他高级功能,如Broadcast变量共享数据,使用累加器进行计数或统计等,来进一步提高性能和效率。 ### 回答3: Spark RDD 是 Spark 提供的一种基于内存的分布式数据处理模型,其核心数据结构是弹性分布式数据集(RDD)。 在 Spark RDD 中,分组TopN 是一种常见的需求,即对 RDD 中的数据按某个字段进行分组,并出每个分组中字段值最大的前 N 个数据。 下面以一个示例来说明分组 TopN 的用法和优化方法: 假设有一个包含学生信息的 RDD,其中每条数据都包括学生的学科和分数,我们希望对每个学科出分数最高的前 3 名学生。 ```python # 创建示例数据 data = [ ("语文", 80), ("数学", 90), ("语文", 85), ("数学", 95), ("语文", 75), ("数学", 92), ("英语", 88) ] rdd = sc.parallelize(data) # 分组TopN top3 = rdd.groupByKey().mapValues(lambda x: sorted(x, reverse=True)[:3]) # 输出结果 for subject, scores in top3.collect(): print(subject, scores) # 输出结果: # 数学 [95, 92, 90] # 语文 [85, 80, 75] # 英语 [88] ``` 在上述代码中,我们先使用 `groupByKey()` 对 RDD 进行分组操作,然后使用 `mapValues()` 对每个分组内的数据进行排序前 3 个值。 这种方式的优化点在于,通过将分组操作和 TopN 操作分开,可以减轻数据倾斜的问题。同时,对每个分组进行排序会占用大量计算资源,可以考虑将数据转换为 Pair RDD,并利用 Spark 提供的 `top()` 算子来优化 TopN 的操作。 ```python # 转换为 Pair RDD pair_rdd = rdd.map(lambda x: (x[0], x[1])) # 分组TopN,使用top()算子代替排序操作 top3 = pair_rdd.groupByKey().mapValues(lambda x: sorted(x, reverse=True)).mapValues(lambda x: x[:3]) # 输出结果 for subject, scores in top3.collect(): print(subject, scores) # 输出结果: # 数学 [95, 92, 90] # 语文 [85, 80, 75] # 英语 [88] ``` 通过以上优化,我们可以更好地处理大规模数据集下的分组 TopN 的需求,提高计算性能和资源利用率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值