牛客_非技术快速入门_题目总结
SQL29 计算用户的平均次日留存率
描述
题目:现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。
示例:question_practice_detail
id device_id quest_id result date
1 2138 111 wrong 2021-05-03
2 3214 112 wrong
2021-05-09
3 3214 113 wrong
2021-06-15
4 6543 111 right 2021-08-13
5 2315 115 right
2021-08-13
6 2315 116 right
2021-08-14
7 2315 117 wrong
2021-08-15
……
根据示例,你的查询应返回以下结果:
avg_ret
0.3000
思路
概率计算:第二天刷题的天数/用户刷题天数总和
第二天刷题的条件筛选表示:datediff(date1, date2)=1
初步思路用连接查询q1,q2分别表示第一天、第二天:连接条件q1.device_id=q2.device_id and datediff(q2.date,q1.date)=1
。如果使用内连接,则可能出现q1和q2在连接时由于datediff(q2.date,q1.date)=1
条件导致部分天数被筛掉,无法统计总天数。所以这里需要用外连接。
第二天刷题的天数:正常想q2表示第二天,则表示为count(q2.date)。但是细想连接时,可能出现用户可能做了不止一题的问题,这时q2.date就会重复。说明,同一个用户的date可能会重复。这时需要对(q1.device_id,q1.date)去重。
select count(distinct q2.device_id,q2.date)/count(distinct q1.device_id,q1.date) as avg_ret
from question_practice_detail as q1 left outer join question_practice_detail as q2
on q1.device_id=q2.device_id and datediff(q2.date,q1.date)=1;
SQL33 找出每个学校GPA最低的同学
描述
题目:现在运营想要找到每个学校gpa最低的同学来做调研,请你取出每个学校的最低gpa。
示例:user_profile
id device_id gender age university gpa active_days_within_30 question_cnt
answer_cnt
1 2138 male 21 北京大学 3.4 7 2 12
2 3214 male 复旦大学 4 15 5 25
3 6543 female 20 北京大学 3.2 12 3 30
4 2315 female 23 浙江大学 3.6 5 1 2
5 5432 male 25 山东大学 3.8 20 15 70
6 2131 male 28 山东大学 3.3 15 7 13
7 4321 female 26 复旦大学 3.6 9 6 52
根据示例,你的查询结果应参考以下格式,输出结果按university升序排序:
device_id university gpa
6543 北京大学 3.2000
4321 复旦大学 3.6000
2131 山东大学 3.3000
2315 浙江大学 3.6000
思路
如果只查询学校和最低GPA使用group by
和min
即可结束战斗。但是,需要查询相应的id。此时对于又要查询统计信息又要查询基础信息(非group by下的字段),可以用子查询,但稍显复杂。这里引入窗口函数来解决问题。
窗口函数
遇到既要分组统计数据又要查询原始数据行的情况下,使用MySql的窗口函数。窗口函数用于在查询结果中执行聚合、排序和分析操作,同时保留原始数据的行。窗口函数允许您在不对查询结果进行分组的情况下,根据特定的窗口(或框架)来计算值。
语法
function_name() OVER ([PARTITION BY partition_expression][ORDER BY order_expression [ASC | DESC]][window_frame_clause]
) AS alias
function_name()
: 要应用的聚合函数或分析函数,如SUM()
,AVG()
,ROW_NUMBER()
,RANK()
, 等等。PARTITION BY partition_expression
: 可选项,类似于group by
根据指定的表达式对结果集进行分区,使窗口函数在每个分区内进行计算。ORDER BY order_expression [ASC | DESC]
: 可选项,指定对窗口内的行进行排序,以便窗口函数能够基于排序顺序计算结果。window_frame_clause
: 可选项,用于定义窗口的范围或框架,例如确定窗口中要包含的行的范围。alias
: 可选项,定义窗口函数的输出列的别名。
示例
表结构和数据
CREATE TABLE students (student_id INT PRIMARY KEY,student_name VARCHAR(50),subject VARCHAR(50),score INT,class_id INT
);INSERT INTO students (student_id, student_name, subject, score, class_id)
VALUES(1, 'Alice', 'Math', 85, 101),(2, 'Bob', 'Math', 90, 101),(3, 'Charlie', 'Math', 75, 102),(4, 'David', 'Science', 88, 102),(5, 'Emma', 'Science', 92, 103),(6, 'Frank', 'English', 80, 103),(7, 'Grace', 'English', 85, 102);
使用 ROW_NUMBER()
计算每个学生的行号
SELECTstudent_name,subject,score,class_id,ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num
FROM students;
结果:
+--------------+---------+-------+----------+---------+
| student_name | subject | score | class_id | row_num |
+--------------+---------+-------+----------+---------+
| Emma | Science | 92 | 103 | 1 |
| Bob | Math | 90 | 101 | 2 |
| David | Science | 88 | 102 | 3 |
| Grace | English | 85 | 102 | 4 |
| Alice | Math | 85 | 101 | 5 |
| Frank | English | 80 | 103 | 6 |
| Charlie | Math | 75 | 102 | 7 |
+--------------+---------+-------+----------+---------+
使用 RANK() 计算每个科目分数的排名(允许并列排名)
SELECTstudent_name,subject,score,class_id,RANK() OVER (PARTITION BY subject ORDER BY score DESC) AS subject_rank
FROM students;
结果:
+--------------+---------+-------+----------+--------------+
| student_name | subject | score | class_id | subject_rank |
+--------------+---------+-------+----------+--------------+
| Bob | Math | 90 | 101 | 1 |
| Alice | Math | 85 | 101 | 2 |
| Charlie | Math | 75 | 102 | 3 |
| Emma | Science | 92 | 103 | 1 |
| David | Science | 88 | 102 | 2 |
| Grace | English | 85 | 102 | 1 |
| Frank | English | 80 | 103 | 2 |
+--------------+---------+-------+----------+--------------+
使用 SUM() 计算每个班级累计总分
SELECTstudent_name,subject,score,class_id,SUM(score) OVER (PARTITION BY class_id) AS class_total_score
FROM students;
结果:
+--------------+---------+-------+----------+-----------------+
| student_name | subject | score | class_id | class_total_score |
+--------------+---------+-------+----------+-----------------+
| Alice | Math | 85 | 101 | 175 |
| Bob | Math | 90 | 101 | 175 |
| Charlie | Math | 75 | 102 | 163 |
| David | Science | 88 | 102 | 163 |
| Grace | English | 85 | 102 | 163 |
| Emma | Science | 92 | 103 | 172 |
| Frank | English | 80 | 103 | 172 |
+--------------+---------+-------+----------+-----------------+
再回到原题:
select device_id, university, gpa from (select device_id, university, gpa, row_number() over (partition by university order by gpa) as rn from user_profile) rk where rn = 1 order by university;
SQL35 浙大不同难度题目的正确率
描述
题目:现在运营想要了解浙江大学的用户在不同难度题目下答题的正确率情况,请取出相应数据,并按照准确率升序输出。
示例: user_profile
id device_id gender age university gpa active_days_within_30
question_cnt
answer_cnt
1 2138 male 21 北京大学 3.4 7 2 12
2 3214 male 复旦大学 4 15 5 25
3 6543 female 20 北京大学 3.2 12 3 30
4 2315 female 23 浙江大学 3.6 5 1 2
5 5432 male 25 山东大学 3.8 20 15 70
6 2131 male 28 山东大学 3.3 15 7 13
7 4321 female 26 复旦大学 3.6 9 6 52
示例: question_practice_detail
id device_id question_id result
1 2138 111 wrong
2 3214 112 wrong
3 3214 113 wrong
4 6543 111 right
5 2315 115 right
6 2315 116 right
7 2315 117 wrong
示例: question_detail
question_id difficult_level
111 hard
112 medium
113 easy
115 easy
116 medium
117 easy
根据示例,你的查询应返回以下结果:
difficult_level correct_rate
easy
0.5000
medium
1.0000
思路
正确率:正确题数/总做题数。
select c.difficult_level, count(case b.result when 'right' then 1 else null end)/count(*) correct_rate from user_profile a, question_practice_detail b, question_detail c where a.device_id = b.device_id and b.question_id = c.question_id and a.university = "浙江大学" group by c.difficult_level order by correct_rate;