MySQL五十题
1. 查询"01"课程比"02"课程成绩高的学生信息及课程分数
SELECT
a.s_id,
student.s_name,
a.s_score '01',
b.s_score '02'
FROM
( SELECT s_id, c_id, s_score FROM score WHERE c_id = '01' ) AS a
INNER JOIN ( SELECT s_id, c_id, s_score FROM score WHERE c_id = '02' ) AS b ON a.s_id = b.s_id
INNER JOIN student ON student.s_id = a.s_id
WHERE
a.s_score > b.s_score
想获得
先获得 在成绩表里筛出 a表:课程01 , b表同理
然后通过s_id关联,就可以获得学生的两门成绩
筛选课程01>课程02
关联学生表补充学生信息
2. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
SELECT student.s_id,student.s_name,round(avg,2) as avg
from student
INNER JOIN
(
SELECT s_id,avg(s_score) as avg
FROM score
GROUP BY s_id HAVING avg(s_score)>=60
) t
on student.s_id=t.s_id
round(avg(s_score),2) 表示对 avg(s_score) 进行四舍五入到小数点后两位
用分数表先根据id分组查出每个学生的平均成绩,然后内连接学生表查信息
注意给avg(s_score)起个别名,不然第一行直接写的话会说找不到s_score
3. 查询所有同学的学编号、学生姓名、选课总数、所有课程的总成绩
SELECT
student.s_id,student.s_name,count( score.s_id ),
sum(CASE WHEN score.s_score IS NULL THEN 0 ELSE score.s_score END)
FROM student
LEFT JOIN score ON score.s_id = student.s_id
GROUP BY
s_id,student.s_name
学生有可能没有成绩,所以不要先查子表再套学生表了,直接拉大通铺后再分组
规范:如果有group by,查询内容就能写gruop by里有的信息和计算函数,根据id和name的分组结果是一样的,所以都写,这样就可以在第二行写上去了
然后学会使用case when来规避null
4. 查询姓“李”的老师的数量
SELECT count(teacher.t_name)
from teacher
where teacher.t_name like '李%'
若需要对名字去重,则为 count(distinct teacher.t_name),但distinct效率低,优化时可能不会使用
*5.查询没学过"张三"老师讲授的任何一门课程的学生姓名
SELECT s_name from student where s_id not in(
SELECT s_id from score where c_id=(
SELECT c_id from course where t_id=(
SELECT t_id from teacher where t_name = '张三')))
SELECT s_id,s_name from student
WHERE s_id not in(
SELECT s_id from score
INNER JOIN course on score.c_id=course.c_id
INNER JOIN teacher on teacher.t_id=course.t_id
WHERE teacher.t_name='张三')
做一个这样的大表,筛选教师姓名为张三的
6. 查询学过“张三”老师授课的同学的信息
上题的 not in 改为 in
*7.查询同时存在"01"课程和"02"课程的学生id和姓名
SELECT student.s_id,student.s_name from student where s_id in(
SELECT a.s_id from
(SELECT s_id from score WHERE c_id != '01') a
INNER JOIN
(SELECT s_id from score WHERE c_id = '02') b
on a.s_id=b.s_id)
9.查询所有课程小于60分的学生学号姓名
SELECT a.s_id from
(SELECT s_id,count(s_id) as c1 from score WHERE s_score<60 GROUP BY s_id) as a
-- 每个同学课程小于60的课程数
INNER JOIN
(SELECT s_id,count(c_id) as c2 from score GROUP BY s_id) as b -- 每个同学共学了几门课
on a.s_id=b.s_id
WHERE a.c1=b.c2
10.查询没有学全所有课程的同学的信息
SELECT student.* from student where student.s_id in(
SELECT student.s_id from student LEFT JOIN score on student.s_id=score.s_id
GROUP BY student.s_id HAVING count(c_id)<(SELECT count(c_id) from course)
)
不可以把两个表内连接!一定左外连接!不然会漏掉啥课都没选的学生!!
SELECT student.* from student where student.s_id not in(
SELECT s_id from score
GROUP BY s_id HAVING count(s_id)=(SELECT count(c_id) from course)
)
法二:先查课程全选的学生,然后排除掉
11.查询至少有一门课与学号为01的同学所学相同的同学的信息
SELECT DISTINCT student.s_id,s_name from student
LEFT JOIN score on student.s_id=score.s_id where c_id
in (SELECT c_id from score where s_id='01') and student.s_id!='01'
*12.查询和"01"号的同学学习的课程完全相同的其他同学的信息
SELECT * from student where s_id in( -- 一定在第一个表里
SELECT s_id from score WHERE s_id!='01'
GROUP BY s_id -- 与01同学的课程数一样的
HAVING count(c_id)=(SELECT count(c_id) from score WHERE s_id='01'))
and s_id not in( -- 不能在这个表里
SELECT DISTINCT s_id from score WHERE c_id not in -- 哪些同学修了别的课
(SELECT c_id from score where s_id='01')) -- 01同学修了哪些课
01同学选了1,2,3三门课
表一:选出所学的课不在(1,2,3)的同学 排除
表二:剩下的同学肯定选了(1,2,3)里的课,选出所学课程数是否等于3
*15. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
SELECT student.s_id,s_name,avg(s_score) from student
INNER JOIN score on student.s_id=score.s_id -- 大通铺
where student.s_id in(-- 两门及以上不及格的同学
SELECT s_id from score WHERE s_score<60 GROUP BY s_id HAVING count(c_id)>=2)
GROUP BY s_id,s_name
先拉大通铺,最后gruop by
16. 查询"01"课程分数小于60,按分数降序排列的学生信息
SELECT student.*,c_id,s_score from student INNER JOIN score on student.s_id=score.s_id
where c_id='01' and s_score<60
ORDER BY s_score desc
先拉大通铺
*17. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
SELECT student.s_id,s_name,
max(case when c_id='01' then s_score else null end) '01',
max(case when c_id='02' then s_score else null end) '02',
max(case when c_id='03' then s_score else null end) '03',
avg(s_score)
from student
LEFT JOIN score on student.s_id=score.s_id
GROUP BY student.s_id,s_name
ORDER BY avg(s_score) DESC
*18.查询各科成绩最高分,最低分,平均分,及格率,中等率,优良率,优秀率
课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
SELECT score.c_id,c_name,max(s_score),min(s_score),avg(s_score),
concat(round(sum(case when s_score>=60 then 1 else 0 end)/count(s_id)*100,2),'%') 及格率,
concat(round(sum(case when s_score BETWEEN 70 and 80 then 1 else 0 end)/count(s_id)*100,2),'%') 中等率,
concat(round(sum(case when s_score BETWEEN 80 and 90 then 1 else 0 end)/count(s_id)*100,2),'%') 优良率,
concat(round(sum(case when s_score>=90 then 1 else 0 end)/count(*)*100,2),'%') 优秀率
from score INNER JOIN course on course.c_id=score.c_id
GROUP BY c_id,c_name
19. 按各科平均成绩进行排序,并显示排名,Score重复时保留名次空缺
SELECT dense_rank() over(partition by score.c_id ORDER BY s_score DESC) as ranked,
score.c_id,c_name,student.s_id,s_name,s_score from score
INNER JOIN course on course.c_id=score.c_id
INNER JOIN student on student.s_id=score.s_id
dense_rank() over(partition by score.c_id ORDER BY s_score DESC)
根据c_id分组,组内排名,根据score降序排名
20. 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
SELECT rank() over(ORDER BY sum(s_score) desc),s_id,sum(s_score)
from score GROUP BY s_id
21、查询不同老师所教不同课程平均分从高到低显示
SELECT teacher.t_id,t_name, score.c_id,c_name,avg(s_score) avg from score
INNER JOIN course on score.c_id=course.c_id
INNER JOIN teacher on teacher.t_id=course.t_id
GROUP BY score.c_id ,c_name,teacher.t_id,t_name
ORDER BY avg desc
*22、查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
SELECT * from(
SELECT student.s_id,s_name,c_id,s_score,
row_number () over(partition by c_id ORDER BY s_score desc) m
from score INNER JOIN student on score.s_id=student.s_id
) a where a.m in (2,3)
您试图在 WHERE
子句中直接使用窗口函数 ROW_NUMBER()
生成的列 ran
。在大多数 SQL 数据库系统中,窗口函数的结果不能直接在 WHERE
子句中使用,因为 WHERE
子句在窗口函数之前执行
所以要最外面套一个 SELECT * from(
*23. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0]及所占百分比
SELECT course.c_id,c_name,
count(case when s_score<=100 and s_score>85 then 88888 else null end) '[100,85)',
sum(case when s_score<=85 and s_score>70 then 1 else 0 end) '[85,70)',
sum(case when s_score<=70 and s_score>60 then 1 else 0 end) '[70,60)',
sum(case when s_score<60 then 1 else 0 end) '(<60)'
from course INNER JOIN score on score.c_id=course.c_id
GROUP BY c_id,c_name
24.查询学生平均成绩及其名次
SELECT s_id,avg(s_score),ROW_NUMBER() over(ORDER BY avg(s_score) desc)
from score GROUP BY s_id
25. 查询各科成绩前三名的记录
26. 查询每门课程被选修的学生数
SELECT score.c_id,c_name,count(score.c_id)
from score INNER JOIN course on score.c_id=course.c_id
GROUP BY score.c_id,c_name
e27. 查询只选修两门课程的学生学号和姓名
SELECT score.s_id,s_name from score
INNER JOIN student on score.s_id=student.s_id
GROUP BY score.s_id,s_name HAVING count(score.s_id)=2
28. 查询男生女生人数
SELECT s_sex,count(s_id) from student GROUP BY s_sex
SELECT
count(case when s_sex='男' then 999 else null end) '男生人数',
sum(case when s_sex='女' then 1 else 0 end) '女生人数'
from student
e29. 查询名字中含有“风”字的学生信息
SELECT * from student where s_name like '%风%'
31. 查询1990年出生的学生名单
SELECT * from student WHERE year(s_birth)=1990
e32. 查询平均成绩大于等于85的所有学生的学号,姓名和平均成绩
SELECT student.s_id,s_name,avg(s_score) from student
INNER JOIN score on student.s_id=score.s_id
GROUP BY student.s_id,s_name HAVING avg(s_score)>=85
33. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT score.c_id,c_name,avg(s_score) from score
INNER JOIN course on course.c_id=score.c_id
GROUP BY score.c_id,c_name
ORDER BY avg(s_score) desc,c_id asc
34. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
SELECT s_name,s_score from score
INNER JOIN course on score.c_id=course.c_id
INNER JOIN student on score.s_id=student.s_id
where c_name='数学' and s_score<60
*35. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
SELECT student.s_id,s_name,
max(case when c_name='语文' then score.s_score else null end) '语文',
max(case when c_name='数学' then score.s_score else null end) '数学',
max(case when c_name='英语' then score.s_score else null end) '英语'
from student
left JOIN score on student.s_id=score.s_id
left JOIN course on course.c_id=score.c_id
GROUP BY student.s_id,s_name
如果gruop by后之间查成绩,case when c_name=数学后给数学成绩赋值,但只会返回本列第一个
e36. 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
SELECT s_name,c_name,s_score from student
INNER JOIN score on score.s_id=student.s_id
INNER JOIN course on course.c_id=score.c_id
where s_score>=70
e37. 查询不及格的课程并按课程号从大到小排列
SELECT student.s_id,s_name,course.c_id,c_name,s_score from score
INNER JOIN course on score.c_id=course.c_id
INNER JOIN student on student.s_id=score.s_id
where s_score<60 ORDER BY c_id desc
e38. 查询课程编号为 03 且课程成绩在 80 分以上的学生的学号和姓名
SELECT student.s_id,s_name,c_id,s_score from score
INNER JOIN student on student.s_id=score.s_id
where c_id='03' and s_score>80
e39. 求每门课程的学生人数
SELECT score.c_id,c_name,count(score.c_id) from score
right JOIN course on score.c_id=course.c_id
GROUP BY score.c_id,c_name
40.查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT s_name,s_score from student
INNER JOIN score on student.s_id=score.s_id
INNER JOIN course on course.c_id=score.c_id
INNER JOIN teacher on course.t_id=teacher.t_id
where t_name='张三'
ORDER BY s_score DESC LIMIT 0,1
*41. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
SELECT * from score WHERE s_score in(
SELECT s_score from score GROUP BY s_score HAVING count(s_score)>1)
43. 统计每门课程的学生选修人数(超过 5 门的课程才统计)。输出课程号和选修人数,按人数降序、课程升序排列
SELECT c_id,count(DISTINCT s_id) FROM score GROUP BY c_id HAVING count(c_id)>5
ORDER BY count(c_id) desc,c_id asc
count(DISTINCT s_id) 是为了防止有人重修
e44. 检索至少选修两门课程的学生学号
SELECT s_id from score GROUP BY s_id HAVING count(s_id)>=2
45. 查询选修了全部课程的学生信息
SELECT s_id from score GROUP BY s_id HAVING count(s_id)=
(SELECT count(c_id) from course)
46. 查询各学生的年龄,只按年份来算
SELECT s_id,s_birth,
floor(datediff(CURDATE(),s_birth)/365)
from student;
48. 查询下周过生日的学生
SELECT * from student where
week(concat(year(curdate()),substring(s_birth,6,5)),1)=week(curdate(),1)+1
49. 查询本月过生日的学生
SELECT * from student where month(s_birth)=month(current_date())
50. 查询下个月过生日的学生
SELECT * from student where
case when month(curdate()=12) then month(s_birth)=1
else month(s_birth)=month(curdate())+1 end
小心下个月是13月