选ROLLUP还是UNION ALL?MYSQL版本问题?

每个学校的平均年龄和平均绩点及整体情况

https://www.nowcoder.com/practice/d686ac1d09d94441be91475843797d2d

1. 题意

  • 给你一张表user_profile,请你统计出每个学校和总体的平均用户年龄、平均用户绩点,这些数据需要保留三位小数

2. 思路

  • 首先,我们需要统计的是每个学校的数据那么必然要通过学校进行分组,因此GROUP BY子句是必不可少的
  • 求平均数则可以使用AVG函数,而保留小数则可以使用ROUN函数
  • 最后,难点就在于怎么同时获取总体的数据了

2.1 UNION ALL

  • 难点既然在于同时获取分组和总体的数据,那么我们不同时获取不就行了
  • 因此我们可以将分组的数据和总体的数据分开来写

总体数据:

SELECT 
	'总体' AS 'university',
	ROUND(AVG(age), 3) AS 'avg_age',
	ROUND(AVG(gpa), 3) AS 'avg_gpa'
FROM 
	user_profile

分组数据:

SELECT 
	university AS 'university',
	ROUND(AVG(age), 3) AS 'avg_age',
	ROUND(AVG(gpa), 3) AS 'avg_gpa'
FROM
	user_profile
GROUP BY university

  • 最后我们只需要将这两个部分的SQL合并在一起即可,这里可以使用UNION或者UNION ALL,两者都可以通过,但UNION会进行去重,而我们这里不需要去重,所以选择UNION ALL在性能上会更好一些

完整SQL:

SELECT 
	'总体' AS 'university',
	ROUND(AVG(age), 3) AS 'avg_age',
	ROUND(AVG(gpa), 3) AS 'avg_gpa'
FROM 
	user_profile
UNION ALL
SELECT 
	university AS 'university',
	ROUND(AVG(age), 3) AS 'avg_age',
	ROUND(AVG(gpa), 3) AS 'avg_gpa'
FROM
	user_profile
GROUP BY university

2.2 WITH ROLLUP

  • 上述SQL中,我们其实写了不少重复的代码,那么有没有一种函数能够在分组的同时还能够获取总体的数据呢?
  • 当然有,它就是WITH ROLLUP,不熟悉的朋友可以去看看官方文档,该函数会将总体的数据单独统计为一行,但因为其是总体数据,所以不会根据分组来查询对应的数据,因此该函数对应的分组字段为"NULL",而不是我们所写的"university"

WITH ROLLUP官方文档(MySQL8.0): https://dev.mysql.com/doc/refman/8.0/en/group-by-modifiers.html

  • 既然有这个特性,那么我们在处理的时候,就能够根据其返回的"NULL"进行分支处理,即将university字段为NULL的改为题目要求的"总体"即可,这里我们可以使用IFNULL,也可以使用CASE WHEN,两种写法如下:
SELECT 
	CASE WHEN ISNULL(university) THEN '总体' ELSE university END AS 'university',
	ROUND(AVG(age), 3) AS 'avg_age',
	ROUND(AVG(gpa), 3) AS 'avg_gpa'
FROM
	user_profile
GROUP BY university
WITH ROLLUP
ORDER BY university

SELECT 
	IFNULL(university, '总体') AS 'university',
	ROUND(AVG(age), 3) AS 'avg_age',
	ROUND(AVG(gpa), 3) AS 'avg_gpa'
FROM
	user_profile
GROUP BY university
WITH ROLLUP
ORDER BY university
  • 看起来两种写法都行,不过为了更好的移植性,最好选择使用CASE WHEN的写法,当然,解题就无所谓了
  • 注意这里我们在最后添加了一句ORDER BY子句,这是因为我们最后查询出来的结果中,总体数据会排在最后,而结果要求排在最前面,因此我们需要进行一次排序

2.3 选择

  • 既然UNION ALL和WITH ROLLUP的写法都行,那么我们是不是无脑选择写起来简单的就行了呢?这就要说到MySQL版本了
  • 各位注意观察的话就会发现牛客网使用的MySQL版本为8.0,如果上述WITH ROLLUP写法的SQL在我们本地/云端的5.7版本的MySQL上运行的话,就会出现问题:

  • 这样一来,在限制顺序的情况下,我们在MySQL5.7中就无法使用WITH ROLLUP来满足这道题目的需求了,所以也提醒各位,当发现在线网站上能够运行通过但自己测试的时候出问题时,先检查一下两个环境的版本是否一致。

全部评论

相关推荐

秋招结束已经一段时间了 一直在忙着毕业的事情 浅浅总结一下自己的秋招经历吧~本人BG双非硕 后端选手 有一段小厂+腾讯暑期实习腾讯暑期转正loser秋招结束已经结束了有一段时间了总结一下秋招历程最大的感受就是秋招比起暑期更加卡学历秋招总共投了60多家吧一直面 一直挂也投了两家银行科技岗 都走到终面体检了都拒了(总体感觉本地的银行还是挺容易过的)可能本人更想去私企 并且银行也挺卷听说一直到11月就只有一家小厂的offer并签约当保底然后也突然被WXG捞了 本来都不对腾讯抱有希望了可能经过一整个秋招的面试积累吧 以及本人有ACM经历 WXG整体面试以做题偏多(一二面做了5道题 4道hard) 比较合自己胃口 差不多半个月就把五轮面试过了进入录用评估 但也一直没有结果到后面也陆陆续续有几家中厂也终面过泡池子一直到12月初华子给开了base杭州 14a因为华子公积金的原因 和小厂薪资上差距不大 所以也一直犹豫是否毁约签华子 但是内心也还对WXG抱有一丝幻想(虽然一直没有保温也没有任何消息)然后一直到12月中下旬 华子要求去现场签约了 但是WXG还是没有消息 然后就连续发邮件和打电话催了好多次 还是回复耐心等待直到华子签约那天 经过内心挣扎已经决定毁约签华子了 可能还是想平台更大一点吧 然后最戏剧性的一幕来了 就在我发毁约邮件没有5秒 WXG打电话开奖了 并且开奖也十分有诚意 最终还是没有签约成功华子 研究生期间也打了很多次华子的比赛还是对华子有感情的555整个秋招都是伴随着焦虑的 我认为自己也是秋招大部分人的画像 屡屡碰壁后不断怀疑自己 但是可能自己也比较幸运吧 但是也感谢自己在一次次陷入迷茫都没有放弃自己 还是一直努力背八股 刷题也祝各位牛友们共勉 就算暂时没有好的offer 不放弃一定会有好的结果的!!
点赞 评论 收藏
分享
评论
15
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务