好久没写SQL,基本的语法有点生疏,网上参考了 [博客一][1] 、 [博客二][2] 来练习:
其中还涉及MySQL8中的窗口函数
基本数据
-- 1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数
select * from
(
select a.s_no,s1,s2 from
(select s_no,score s1 from sc where sc.c_no = '01') a
join
(select s_no,score s2 from sc where sc.c_no = '02') b
on a.s_no = b.s_no and s1>s2
) tmp
join student on student.no = tmp.s_no;
-- 2 查询同时存在" 01 "课程和" 02 "课程的情况
select student.* from
(
select a.s_no from
(select s_no from sc where sc.c_no = '01') a
inner join
(select s_no from sc where sc.c_no = '02') b
on a.s_no = b.s_no
) tmp
join student on student.no = tmp.s_no;
-- 3 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
select student.* from
(
select a.s_no from
(select s_no from sc where sc.c_no = '01') a
left join
(select s_no from sc where sc.c_no = '02') b
on a.s_no = b.s_no
) tmp
join student on student.no = tmp.s_no;
-- 4 查询不存在" 01 "课程但存在" 02 "课程的情况
select * from sc
join student on student.no = sc.s_no
where `c_no` = '02' and s_no not in
(
(select s_no from sc where sc.c_no = '01')
)
-- 5. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
select * from student join
(
select s_no, avg(score) from sc group by s_no HAVING avg(score) > 60
) tmp
on student.no = tmp.s_no;
-- 6. 查询在 SC 表存在成绩的学生信息
select DISTINCT s.* from student s join sc on s.no = sc.s_no and score is not null;
-- 7. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
select s.no,s.name,tmp.course_total,tmp.score_total from student s
left join
(
select sc.s_no,count(*) as course_total, sum(sc.score) as score_total from sc group by sc.s_no
) tmp
on s.no=tmp.s_no;
-- 8 查有成绩的学生信息
select s.no,s.name,tmp.course_total,tmp.score_total from student s
left join
(
select sc.s_no,count(*) as course_total, sum(sc.score) as score_total from sc group by sc.s_no
) tmp
on s.no=tmp.s_no and tmp.score_total is not null;
-- 9 查询「李」姓老师的数量
select count(*) li_num from teacher where name like '李%';
-- 10 查询学过「张三」老师授课的同学的信息
select s_no from teacher t
join course on t.`no` = course.t_no and t.`name` = '张三'
join sc on course.`no` = sc.c_no;
-- 11 查询没有学全所有课程的同学的信息
select s_no,count(*) from sc group by s_no having count(*) <> 3;
-- 12 查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
select * from student where no in
(select distinct s_no from sc where c_no in (select c_no from sc where s_no = '01'))
-- 13 查询和" 01 "号的同学学习的课程完全相同的其他同学的信息
-- 赶紧没什么意义,知道了01课程为3的前提,才有的答案
SELECT * FROM student
WHERE no IN
(SELECT s_no
FROM sc
WHERE c_no IN
(
SELECT DISTINCT c_no
FROM sc
WHERE s_no = "01"
)
AND s_no <> "01"
GROUP BY S_no
HAVING COUNT(c_no)>=3);
-- 14. 查询没学过"张三"老师讲授的任一门课程的学生姓名
select name from student where no not in (
select sc.s_no from teacher t
inner join course c on t.no = c.t_no and t.`name`='张三'
inner join sc on c.`no`= sc.c_no);
-- 15. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
select s_no,AVG(score) from sc where score < 60 GROUP BY s_no HAVING count(*) >=2
-- 16. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息
select * from sc
join student s on sc.s_no = s.no
and c_no = '01' and score < 60
ORDER BY score desc
-- 17. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
select sc.*,tmp.avg from sc join (
select s_no,AVG(score) avg from sc GROUP BY s_no
) tmp on sc.s_no = tmp.s_no order by tmp.avg desc ;
-- 18. 查询各科成绩最高分、最低分和平均分:
-- 以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率 ,选修人数
-- 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
-- 要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
select c_no, MAX(score),MIN(score),AVG(score),
concat(round(100 * (sum(case when sc.score >= 60 then 1 else 0 end)/count(*)),2),'%') as 及格率,
concat(round(100 * (sum(case when sc.score >= 70 and sc.score < 80 then 1 else 0 end)/count(*)),2),'%') as 中等率,
concat(round(100 * (sum(case when sc.score >= 80 and sc.score < 90 then 1 else 0 end)/count(*)),2),'%') as 优良率,
concat(round(100 * (sum(case when sc.score >= 90 then 1 else 0 end)/count(*)),2),'%') as 优秀率,
COUNT(*) as 选秀人数
from sc GROUP BY c_no
-- 19. 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
-- 5.7版本的mysql没有rank窗口函数,使用下边这种方式查询,在mysql8上测试保持
select if(c_no_up is null or c_no <> c_no_up, @tmp:=rank,'同一科目'),if(score = score_up,rank - @tmp ,rank - @tmp + 1) as 名次,@tmp,a.*,b.*
from (select @tmp := 0) t ,
(select @arownum:=@arownum+1 rank, sc.* from sc,(select @arownum:=0) t order by sc.c_no,sc.score desc) a
left join
(select @arownum1:=@arownum1+1 rank_up, sc.s_no s_no_up, sc.c_no c_no_up,sc.score score_up
from sc,(select @arownum1:=1) t order by sc.c_no,sc.score desc) b
on a.rank = b.rank_up
-- mysql8.0
SELECT *,RANK()OVER(partition by c_no ORDER BY score DESC) as 排名 from sc;
-- 20、按各科成绩进行排序,并显示排名, Score 重复时合并名次
SELECT *,dense_rank()OVER(partition by c_no ORDER BY score DESC) as 排名 from sc;
-- 21. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺
SELECT SUM(score) from sc GROUP BY s_no;
SELECT s_no,SUM(score),DENSE_RANK()OVER(ORDER BY sum(score) DESC) as 排名 from sc GROUP BY s_no;
-- 22、 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
SELECT s_no,SUM(score),RANK()OVER(ORDER BY sum(score) DESC) as 排名 from sc GROUP BY s_no;
-- 23. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
select c.no,c.`name`,
(concat(round((sum(case when sc.score > 85 and sc.score <= 100 then 1 else 0 end)/count(*))*100, 2),'%'))'[100-85]',
(concat(round((sum(case when sc.score > 70 and sc.score <= 85 then 1 else 0 end)/count(*))*100, 2),'%'))'[85-70]',
(concat(round((sum(case when sc.score > 60 and sc.score <= 70 then 1 else 0 end)/count(*))*100, 2),'%'))'[70-60]',
(concat(round((sum(case when sc.score > 0 and sc.score <= 60 then 1 else 0 end)/count(*))*100, 2),'%'))'[60-0]'
from course c
join sc on c.`no` = sc.c_no GROUP BY c.`no`,c.`name`
-- 24. 查询各科成绩前三名的记录
select tmp.* from
(
SELECT *,rank()OVER(partition by c_no ORDER BY score DESC ) as sort from sc
) tmp
where tmp.sort < 4;
-- 25. 查询每门课程被选修的学生数
select sc.c_no,count(*) from sc GROUP BY c_no;
-- 26. 查询出只选修两门课程的学生学号和姓名
select s.no,s.name from student s
join sc on s.no = sc.s_no GROUP BY s.no, s.`name` HAVING count(*) =2
-- 27. 查询男生、女生人数
select sex, count(sex) from student GROUP BY sex;
-- 28. 查询名字中含有「风」字的学生信息
select * from student where `name` like '%风%'
-- 29. 查询同名同性学生名单,并统计同名人数
-- 有些疑问,统计出来的也是同名同性的人数
select a.name,a.sex,count(*) from student a
JOIN student b on a.no !=b.no and a.name = b.name and a.sex = b.sex
GROUP BY a.name,a.sex;
select a.name,a.sex,count(name) from student a GROUP BY a.name,a.sex HAVING count(*)>1
-- 30. 查询 1990 年出生的学生名单
SELECT *
from student
where year(age) = "1990";
select * from student where age >= '1990-01-01 00:00:00' and age < '1991-01-01 00:00:00'
-- 31. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
select c_no,avg(score),RANK()over(ORDER BY avg(score) DESC ,c_no ASC ) from sc GROUP BY c_no;
-- 32. 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
select s.no,s.name,avg(sc.score) from student s
join sc on s.no = sc.s_no GROUP BY s.no ,s.name HAVING avg(score) > 85;
-- 33. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
select * from course c
join sc on c.`no`=sc.c_no and c.`name`= '数学'
join student s on sc.s_no = s.`no` and sc.score < 60
-- 34. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
select s.no,s.name,sc.c_no,c.name,sc.score from student s
left join sc on s.no = sc.s_no
left join course c on sc.c_no = c.no;
-- 35. 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
SELECT * from student where no not in (
select s_no from sc where score < 70 GROUP BY s_no
)
-- 36. 查询不及格的课程
select c_no from sc where score < 60 GROUP BY c_no;
-- 37. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
select * from sc where c_no = '01' and score >= 80
-- 38. 求每门课程的学生人数
select c_no,count(*) from sc GROUP BY c_no;
-- 39. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
select * from teacher t
join course c on t.`no`=c.t_no and t.`name`='张三'
join sc on c.`no`=sc.c_no
join student s on sc.s_no=s.no ORDER BY score desc limit 1;
-- 40. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
select * from
(
select s.no,s.name,sc.score ,RANK()over(ORDER BY score DESC) as sort from teacher t
join course c on t.`no`=c.t_no and t.`name`='张三'
join sc on c.`no`=sc.c_no
join student s on sc.s_no=s.no
) tmp
where tmp.sort = 1;
-- 41. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
select * from sc
join student s on sc.s_no=s.no
where score in
(select score from sc GROUP BY score HAVING count(*) > 1)
-- 42. 查询每门功成绩最好的前两名
select s_no from
(
select * ,rank()over(PARTITION by c_no ORDER BY score DESC) as sort from sc
) tmp
where tmp.sort < 3;
-- 43. 统计每门课程的学生选修人数(超过 5 人的课程才统计)。
select c_no, count(*) from sc GROUP BY c_no HAVING count(*) > 5;
-- 44. 检索至少选修两门课程的学生学号
select s_no from sc GROUP BY s_no HAVING count(*) > 2;
-- 45. 查询选修了全部课程的学生信息
select s_no from sc GROUP BY s_no HAVING count(*) = (select count(*) from course);
-- 46. 查询各学生的年龄,只按年份来算
select YEAR(now())-YEAR(age) from student ;
-- 47. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
select age,YEAR(now())-YEAR(age) as 按年算,
(DATE_FORMAT(NOW(),'%Y')-DATE_FORMAT(age,'%Y')-(case when DATE_FORMAT(NOW(),'%m%d')>DATE_FORMAT(age,'%m%d') then 0 else 1 end)) as 按日期算 from student;
-- 48. 查询本周过生日的学生信息
select * from student where WEEK(DATE_FORMAT(NOW(),'%Y%m%d'))=WEEK(age)
-- 49. 查询下周过生日的学生信息
select * from student where WEEK(DATE_FORMAT(NOW(),'%Y%m%d'))+1=WEEK(age)
-- 50. 查询本月过生日的学生信息
select MONTH(NOW());
select * from student where MONTH(NOW())=MONTH(age)
-- 51. 查询下月过生日的学生信息
select * from student where MONTH(NOW())+1=MONTH(age)