# Write your MySQL query statement below
1280. 学生们参加各科测试的次数
学生表: Students
+---------------+---------+ | Column Name | Type | +---------------+---------+ | student_id | int | | student_name | varchar | +---------------+---------+ 主键为 student_id(学生ID),该表内的每一行都记录有学校一名学生的信息。
科目表: Subjects
+--------------+---------+ | Column Name | Type | +--------------+---------+ | subject_name | varchar | +--------------+---------+ 主键为 subject_name(科目名称),每一行记录学校的一门科目名称。
考试表: Examinations
+--------------+---------+ | Column Name | Type | +--------------+---------+ | student_id | int | | subject_name | varchar | +--------------+---------+ 这张表压根没有主键,可能会有重复行。 学生表里的一个学生修读科目表里的每一门科目,而这张考试表的每一行记录就表示学生表里的某个学生参加了一次科目表里某门科目的测试。
要求写一段 SQL 语句,查询出每个学生参加每一门科目测试的次数,结果按 student_id
和 subject_name
排序。
查询结构格式如下所示:
Students table: +------------+--------------+ | student_id | student_name | +------------+--------------+ | 1 | Alice | | 2 | Bob | | 13 | John | | 6 | Alex | +------------+--------------+ Subjects table: +--------------+ | subject_name | +--------------+ | Math | | Physics | | Programming | +--------------+ Examinations table: +------------+--------------+ | student_id | subject_name | +------------+--------------+ | 1 | Math | | 1 | Physics | | 1 | Programming | | 2 | Programming | | 1 | Physics | | 1 | Math | | 13 | Math | | 13 | Programming | | 13 | Physics | | 2 | Math | | 1 | Math | +------------+--------------+ Result table: +------------+--------------+--------------+----------------+ | student_id | student_name | subject_name | attended_exams | +------------+--------------+--------------+----------------+ | 1 | Alice | Math | 3 | | 1 | Alice | Physics | 2 | | 1 | Alice | Programming | 1 | | 2 | Bob | Math | 1 | | 2 | Bob | Physics | 0 | | 2 | Bob | Programming | 1 | | 6 | Alex | Math | 0 | | 6 | Alex | Physics | 0 | | 6 | Alex | Programming | 0 | | 13 | John | Math | 1 | | 13 | John | Physics | 1 | | 13 | John | Programming | 1 | +------------+--------------+--------------+----------------+ 结果表需包含所有学生和所有科目(即便测试次数为0): Alice 参加了 3 次数学测试, 2 次物理测试,以及 1 次编程测试; Bob 参加了 1 次数学测试, 1 次编程测试,没有参加物理测试; Alex 啥测试都没参加; John 参加了数学、物理、编程测试各 1 次。
原站题解
pythondata 解法, 执行用时: 376 ms, 内存消耗: 60.2 MB, 提交时间: 2023-08-09 15:37:07
import pandas as pd def students_and_examinations(students: pd.DataFrame, subjects: pd.DataFrame, examinations: pd.DataFrame) -> pd.DataFrame: # 按 id 和科目分组,并计算考试次数。 grouped = examinations.groupby(['student_id', 'subject_name']).size().reset_index(name='attended_exams') # 获取 (id, subject) 的所有组合 all_id_subjects = pd.merge(students, subjects, how='cross') # 左连接以保留所有组合。 id_subjects_count = pd.merge(all_id_subjects, grouped, on=['student_id', 'subject_name'], how='left') # 数据清理 id_subjects_count['attended_exams'] = id_subjects_count['attended_exams'].fillna(0).astype(int) # 根据'student_id','Subject_name'以升序对 DataFrame 进行排序。 id_subjects_count.sort_values(['student_id', 'subject_name'], inplace=True) return id_subjects_count[['student_id', 'student_name', 'subject_name', 'attended_exams']]
pythondata 解法, 执行用时: 460 ms, 内存消耗: 61.1 MB, 提交时间: 2023-08-09 15:35:15
import pandas as pd def students_and_examinations(students: pd.DataFrame, subjects: pd.DataFrame, examinations: pd.DataFrame) -> pd.DataFrame: # 创建所有可能的学生和科目组合 student_subject_combinations = pd.merge(students, subjects, how='cross') # 为每个考试出席添加一个值为1的列 examinations['attended_exams'] = 1 # 将组合与考试表合并以获取出席考试次数 result = pd.merge(student_subject_combinations, examinations, how='left', on=['student_id', 'subject_name']) # 按学生ID、学生姓名和科目名称分组,计数出席考试次数,然后按要求排序结果 result = result.groupby(['student_id', 'student_name', 'subject_name'], as_index=False)['attended_exams'].count() result = result.sort_values(['student_id', 'subject_name']) return result
mysql 解法, 执行用时: 746 ms, 内存消耗: 0 B, 提交时间: 2023-04-02 11:45:55
# Write your MySQL query statement below SELECT stu.student_id AS 'student_id', stu.student_name AS 'student_name', sub.subject_name AS 'subject_name', COUNT(exa.subject_name) AS 'attended_exams' #统计考试登记表中的 FROM Students AS stu CROSS JOIN Subjects AS sub #笛卡尔积 LEFT OUTER JOIN Examinations AS exa ON stu.student_id = exa.student_id AND sub.subject_name = exa.subject_name GROUP BY stu.student_id, sub.subject_name ORDER BY stu.student_id, sub.subject_name ;
mysql 解法, 执行用时: 516 ms, 内存消耗: 0 B, 提交时间: 2023-04-02 11:45:40
# 自连接 with cte1 as ( select * from students,subjects ) select a.student_id, a.student_name, a.subject_name, ifnull(count(b.subject_name),0) as attended_exams from cte1 a left join Examinations b using(student_id,subject_name) group by 1,2,3 order by 1,2,3
mysql 解法, 执行用时: 496 ms, 内存消耗: 0 B, 提交时间: 2023-04-02 11:45:17
# Write your MySQL query statement below select ss.student_id,ss.student_name,ss.subject_name,ifnull(e.attended_exams,0) as 'attended_exams' from (select student_id,student_name,subject_name from Students join Subjects) ss #先链接第一个表,创造出每个学生都有对应的每行科目的记录,就出现了第一至三列的那样的表 left join #第二个表链接起来 (select student_id,subject_name,count(student_id) as attended_exams from Examinations group by student_id,subject_name) e #对成绩表按照id,subject和计数进行分组。 on ss.student_id=e.student_id and ss.subject_name = e.subject_name #把两个表链接起来,用leftjoin确保每一个学生后都有成绩的记录(即使为0) group by ss.student_id,ss.subject_name order by ss.student_id,ss.subject_name
mysql 解法, 执行用时: 681 ms, 内存消耗: 0 B, 提交时间: 2023-04-02 11:45:02
# Write your MySQL query statement below SELECT a.student_id, a.student_name, b.subject_name, COUNT(e.subject_name) AS attended_exams FROM Students a CROSS JOIN Subjects b LEFT JOIN Examinations e ON a.student_id = e.student_id AND b.subject_name = e.subject_name GROUP BY a.student_id, b.subject_name ORDER BY a.student_id, b.subject_name