-
题目:
-
sql建表语句:
-
Create table If Not Exists Student (student_id int, student_name varchar(30)); Create table If Not Exists Exam (exam_id int, student_id int, score int); Truncate table Student; insert into Student (student_id, student_name) values ('1', 'Daniel'); insert into Student (student_id, student_name) values ('2', 'Jade'); insert into Student (student_id, student_name) values ('3', 'Stella'); insert into Student (student_id, student_name) values ('4', 'Jonathan'); insert into Student (student_id, student_name) values ('5', 'Will'); Truncate table Exam; insert into Exam (exam_id, student_id, score) values ('10', '1', '70'); insert into Exam (exam_id, student_id, score) values ('10', '2', '80'); insert into Exam (exam_id, student_id, score) values ('10', '3', '90'); insert into Exam (exam_id, student_id, score) values ('20', '1', '80'); insert into Exam (exam_id, student_id, score) values ('30', '1', '70'); insert into Exam (exam_id, student_id, score) values ('30', '3', '80'); insert into Exam (exam_id, student_id, score) values ('30', '4', '90'); insert into Exam (exam_id, student_id, score) values ('40', '1', '60'); insert into Exam (exam_id, student_id, score) values ('40', '2', '70'); insert into Exam (exam_id, student_id, score) values ('40', '4', '80');
-
分析:首先,我们先看题,题目要求要找出没有当过第一和最后的人,没有参加过考试的不算,我们可以先按照考试id分组,按照分数排序,正序倒序都要,找出每个人在每个考试的排名,然后先取出没有得过第一和最后的人,因为这样会包含在其他考试得过第一或者最后的人,所以我们应该在取出得过第一和最后的id,筛选出在没有得过第一和最后并且也不再得过第一和最后表里的人,然后连接学生表,得到姓名。图表分析:
-
sql实现:
-
with t1 as (select exam_id, student_id, score, rank() over (partition by exam_id order by score) rn1, -- 窗口函数升序 rank() over (partition by exam_id order by score desc) rn2 -- 窗口函数降序 from Exam), t2 as ( select * from t1 where rn1 !=1 and rn2 !=1 -- 找出没有得过第一或者最后一名的考试信息 ), t3 as ( select distinct student_id from t1 where rn1=1 or rn2 =1 -- 找出得过第一或者最后一名的学生id ), t4 as ( select distinct student_id from t2 where student_id not in (select * from t3) -- 筛选出没有得过第一或者最后一名的表里面的人不在得过第一或者最后一名的学生id ) select s1.student_id,student_name from t4,Student s1 where s1.student_id=t4.student_id order by s1.student_id; -- 连接学生表得到姓名 并排序
-
pandas例子:
-
data = [[1, 'Daniel'], [2, 'Jade'], [3, 'Stella'], [4, 'Jonathan'], [5, 'Will']] student = pd.DataFrame(data, columns=['student_id', 'student_name']).astype({'student_id':'Int64', 'student_name':'object'}) data = [[10, 1, 70], [10, 2, 80], [10, 3, 90], [20, 1, 80], [30, 1, 70], [30, 3, 80], [30, 4, 90], [40, 1, 60], [40, 2, 70], [40, 4, 80]] exam = pd.DataFrame(data, columns=['exam_id', 'student_id', 'score']).astype({'exam_id':'Int64', 'student_id':'Int64', 'score':'Int64'})
-
pandas实现:
-
import pandas as pd def find_quiet_students(student: pd.DataFrame, exam: pd.DataFrame) -> pd.DataFrame: exam['rn1']=exam.groupby('exam_id')['score'].rank('dense') -- 按照exam_id分组,score排序:升序 名次可以并列 exam['rn2']=exam.groupby('exam_id')['score'].rank('dense',ascending=False) -- 按照exam_id分组,score排序:降序 名次可以并列 a = exam[(exam['rn1']!=1) & (exam['rn2']!=1)]['student_id'].drop_duplicates() -- 找出没有得过第一或者最后一名的考试信息并去重 b=exam[(exam['rn1']==1) | (exam['rn2']==1)]['student_id'].drop_duplicates() -- 找出得过第一或者最后一名的学生id并去重 a=a[~a.isin(b)] -- 筛选出没有得过第一或者最后一名的表里面的人不在得过第一或者最后一名的学生id 注:~符号代表取反 a=a.to_frame() -- 转换为dataframe对象 c=a.merge(student, how='inner', on='student_id').sort_values(['student_id']) -- 连接姓名表得到姓名,并按照学生ID 排序 return c