查看不同年龄段的用户明细
这个题目要区分上面的那个题目,上面分组了,这里没分组,我一开始就是给这个题目分组了,其实这里压根没有分组
计算用户8月每天的练题数量
问题分解
限定条件:2021年8月,写法有很多种
比如用year/month函数的year(date)=2021 and month(date)=8
比如用date_format函数的date_format(date, "%Y-%m")="202108"
每天:按天分组group by date
题目数量:count(question_id)
计算用户的平均次日留存率
问题分解
限定条件:第二天再来。
解法1:表里的数据可以看作是全部第一天来刷题了的,那么我们需要构造出第二天来了的字段,因此可以考虑用left join把第二天来了的拼起来,限定第二天来了的可以用date_add(date1, interval 1 day)=date2筛选,并用device_id限定是同一个用户。
解法2:用lead函数将同一用户连续两天的记录拼接起来。先按用户分组partition by device_id,再按日期升序排序order by date,再两两拼接(最后一个默认和null拼接),即lead(date) over (partition by device_id order by date)
平均概率:
解法1:可以count(date1)得到左表全部的date记录数作为分母,count(date2)得到右表关联上了的date记录数作为分子,相除即可得到平均概率
解法2:检查date2和date1的日期差是不是为1,是则为1(次日留存了),否则为0(次日未留存),取avg即可得平均概率。
统计每种性别的人数
问题分解
限定条件:无;
每个性别:按性别分组group by gender,但是没有gender字段,需要从profile字段截取,按字符,分割后取出即可。可使用substring_index函数可以按特定字符串截取源字符串。因此,本题可以直接用substring_index(profile, ',', -1)取出性别。
substring_index(FIELD, sep, n)可以将字段FIELD按照sep分隔:
当n大于0时取第n个分隔符(n从1开始)左边的全部内容;
当n小于0时取倒数第n个分隔符(n从-1开始)右边的全部内容;
多少参赛者:计数统计,count(device_id)
三种答案
依旧使用case和like即可简单实现
仅为两项可用if代替case,搭配like使用
提取博客URL中的用户名
问题分解
限定条件:无;
提取字段内信息:个人博客字段中的用户名是被字符/分隔的最后一个子串,使用substring_index函数可以按特定字符串截取源字符串 substring_index(FIELD, sep, n)可以将字段FIELD按照sep分隔: 因此,本题可以用substring_index(blog_url, '/', -1)取出用户名.
(1).当n大于0时取第n个分隔符(n从1开始) 左边 的全部内容;
(2).当n小于0时取 倒数第-n个 分隔符(n从-1开始) 右边 的全部内容;
截取出年龄
查找后多列排序
排序的顺序是完全按照规定执行的,如 order by 字段1,字段2 只有在排序的时候,字段1具多个相同的数据后,才会再按照字段2排序。 如果字段1是唯一的,则不会按照字段2去排序。
查找后降序排列
找出每个学校GPA最低的同学
问题分解
限定条件:gpa最低,看似min(gpa),但是要留意,是每个学校里的最低,不是全局最低。min(gpa)的时候对应同学的ID丢了,直接干是拿不到最低gpa对应的同学ID的;SELECT device_id,university,min(gpa) FROM user_profile GROUP BY university; 因为学校与学生是一对多的关系,如果仅用min求出gpa最低的学生,查询结果中的id与学生不一定是对应的关系,因此此方法错误。
可以看到北京大学gpa的最低值是3.2对应的id是6543,第一种查出来的id是2138,很明显第一种是错的
两种思路
第一种方式是用group by把学校分组,然后计算得到每个学校最低gpa,再去找这个学校里和这个gpa相等的同学ID。注意这样如果最低gpa对应多个同学,都会输出,题目没有明确此种情况,心理明白就行。
第二种方式是利用窗口函数,先按学校分组计算排序gpa,得到最低gpa的记录在用子查询语法拿到需要的列即可。此题中rou_number可以得到排序后的位序,取位序为1即可得到最小值(升序时)。
三种答案
统计复旦用户8月练题情况
问题分解
限定条件:需要是复旦大学的(来自表user_profile.university),8月份练习情况(来自表question_practice_detail.date)
从date中取month:用month函数即可;
总题目:count(question_id)
正确的题目数:sum(if(qpd.result='right', 1, 0))
按列聚合:需要输出每个用户的统计结果,因此加上group by up.device_id
细节问题
8月份没有答题的用户输出形式:题目要求『对于在8月份没有练习过的用户,答题数结果返回0』因此明确使用left join即可,即输出up表中复旦大学的所有用户,如果8月没有练习记录,输出0就好了,这个实现是通过sum(if(qpd.result='right', 1, 0))来实现的,只有result不是right,那就都是0,无论是答错了还是没有答都是0
表头:as语法重命名后两列就好
这里一开始我是先把两张表连接起来(用inner join),再用where去筛选。但是本题目是要求找出复旦大学中所有用户8月份的答题情况,复旦大学的用户中,有可能存在8月份没有答题的用户。若先把两张表连起来再用where筛选限定条件,那么运行结果会把属于复旦大学但是没有答题的用户剔除了,不符合本题要求。
我们要的结果是:复旦大学所有用户8月的作答情况,包含没有作答过的。
浙大不同难度题目的正确率
查找最晚入职员工的所有信息
知识点
ORDER BY 根据指定的列对结果集进行排序,默认按照升序,降序 ORDER BY DESC
LIMIT(m, n) 从第 m + 1 行开始取 n 条记录
最晚员工自然是 hire_data,最晚可以用排序 ORDER BY DESC 降序来得到,然后是获取第一条记录,这样理论上是有 bug 的,因为 hire_data 可能有多个相同的记录.
select * from employees order by hire_date desc limit 0,1 所以这样写不严谨
查找入职员工时间排名倒数第三的员工所有信息
注意事项
- where ...in...和limit是不能一起用的,非要一起用就要做一定的修改,可以用where ...=...代替
若存在多人(如3人)同时在最晚的一天入职的情形,必须要考虑去重(使用distinct或者group by),distinct和group by的执行顺序都在limit前面,因为多个人最后一天入职的话那limit 2,1得到的只是降序后的第三条数据,而不是时间排名倒数第三的数据,其中时间排名倒数第一的就占了多条记录
LIMIT(m, n) 从第 m + 1 行开始取 n 条记录