业务场景
学生表:student(学号,学生姓名,出生年月,性别)
成绩表:score(学号,课程号,成绩)
课程表:course(课程号,课程名称,教师号)
教师表:teacher(教师号,教师姓名)
Mysql 版本:5.6
新建数据库,插入表格、数据
新建学生表格
create table Student(sid varchar(10),sname varchar(10),sage datetime,ssex nvarchar(10));
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-05-20' , '男');
insert into Student values('04' , '李云' , '1990-08-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-03-01' , '女');
insert into Student values('07' , '郑竹' , '1989-07-01' , '女');
insert into Student values('08' , '王菊' , '1990-01-20' , '女');
新建课程表格
create table Course(cid varchar(10),cname varchar(10),tid varchar(10));
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
新建教师表格
create table Teacher(tid varchar(10),tname varchar(10));
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
新建课程表格
create table SC(sid varchar(10),cid varchar(10),score decimal(18,1));
insert into SC values('01' , '01' , 80);
insert into SC values('01' , '02' , 90);
insert into SC values('01' , '03' , 99);
insert into SC values('02' , '01' , 70);
insert into SC values('02' , '02' , 60);
insert into SC values('02' , '03' , 80);
insert into SC values('03' , '01' , 80);
insert into SC values('03' , '02' , 80);
insert into SC values('03' , '03' , 80);
insert into SC values('04' , '01' , 50);
insert into SC values('04' , '02' , 30);
insert into SC values('04' , '03' , 20);
insert into SC values('05' , '01' , 76);
insert into SC values('05' , '02' , 87);
insert into SC values('06' , '01' , 31);
insert into SC values('06' , '03' , 34);
insert into SC values('07' , '02' , 89);
insert into SC values('07' , '03' , 98);
1.查询" 01 “课程比” 02 "课程成绩高的学生的信息及课程分数
思路:找出course01和course02的学生成绩,以学生id链接两表,选择01比02高的学生,再与student表格进行链接
select student.sid,sname,sage,ssex,sc01,sc02 from
(select t1.sid,t1.score as sc01,t2.score as sc02 from
(select * from sc where cid='01') as t1
inner join
(select * from sc where cid='02') as t2
on t1.sid=t2.sid
where t1.score>t2.score) t3 left join student
on student.sid=t3.sid
结果
2. 查询同时存在" 01 “课程和” 02 "课程的情况
思路:分别找出cid=01 和cid=02 两个表,并以sid链接
select a.sid,a.cid,a.score,b.cid,b.score from
(select * from sc where cid='01')a
inner join
(select * from sc where cid='02' )b
on a.sid=b.sid
3. 查询存在" 01 “课程但可能不存在” 02 "课程的情况(不存在时显示为 null )
思路:上一题的基础上改用left join,存在表a中内容,表b中可能不存在
select a.sid,a.cid,a.score,b.cid,b.score from
(select * from sc where cid='01') as a
left join
(select * from sc where cid='02')as b
on a.sid=b.sid
4. 查询不存在" 01 “课程但存在” 02 "课程的情况
思路:先找不存在cid=01,即先找出cid=01所有人,再用not in排除;然后加上cid=02 这一条件
select * from sc where sc.cid not in (select sid from sc where cid='01')
and sc.cid='02'
5.查询平均成绩60分宜的学生和成绩
思路:根据学生成绩分组,求平均,用having语句筛选结果
select sid,avg(score) as avg_sc from sc group by sid having avg_sc>60
结果:
6.查询在sc表存在成绩的学生
思路:在sc存在,用sc表left join 学生表,再用用distinct去重
select distinct sc.sid,s.sname from sc left join student s
on s.sid=sc.sid
7.查询所有学生的学号、姓名、选课数、总成绩
思路:以sid关联student和sc两张表,再用group by 做count和sum的统计
select s.sid,s.sname
,count(sc.cid),sum(sc.score)
from student s inner join sc on s.sid=sc.sid group by s.sid
8. 查询有成绩的学生信息
思路:有两种方法,一种用in,一种用exists。exists判断子表中各行的True or False。当子表数据量更大,exists查询更快
-- select s.sname from student s where exists(select sc.sid from sc where s.sid=sc.sid)
select s.sname from students where s.sid in (Select sc.sid from sc)
结果:
9.查询姓“张”老师的个数
思路:用like和%通配符查询
select count(tname) from teacher where tname like "张%"
10. 查询没有学过“张三”老师课的学生姓名和学号
思路:链接三表sc,course,teacher,找出上过张三课的学生id,再与student链接,用not in求补集
select sid,sname from student where sid not in
(select sc.id from sc
inner join course c on sc.sid=c.sid
inner join teacher t on c.tid=t.tid
where t.tid='张三')
结果:
11.查询没有学全所有课程的同学的信息*
思路:student和sc表left join 找出所有学生的上课情况,竟然有没选课的!
group by sid ,筛选小于总课程数的sid
在student表中,用in选出上述sid
select * from student where sid in
(select a.sid from
(select s.sid,count(distinct sc.cid) cnt from student s left join sc on s.sid=sc.sid group by s.sid
having cnt<(select count(distinct cid) from course)
)a
)
12.查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
说明:与01 有课程交集的所有同学信息, 即选中cid在 01同学cid列表中的同学
select * from student s where s.sid in(
select sc.sid from sc
where sc.cid in (select cid from sc where sid='01') and sc.sid!='01'
)
13.查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息
思路:1.01同学选了01,02,03
2. 选出课不在01,02,03中的同学,排除
3. 剩下的同学选的课肯定是01,02,03的子集,筛选出count为3的就是完全相同的
select * from student where sid in
(select distinct sid from sc where sid not in
(select distinct sid from sc where
cid not in (select cid from sc where sid=01)) and sid!=01
group by sid having count(distinct cid)=3)
14. 查询没学过"张三"老师讲授的任一门课程的学生姓名
思路:1.找出张三老师的所有课
2. 找出所有上过张三老师课的学生
3. 排除上述学生
SELECT SNAME FROM STUDENT WHERE SID NOT IN
(
SELECT distinct SID FROM SC WHERE CID IN
(select cid FROM COURSE WHERE TID=(select tid from teacher where tname='张三'))
)
15. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
思路:1.找出成绩小于60的记录
2.以课程数分组,筛选不及格数大于2门的,求平均分
3. 链接student表
SELECT B.SID,S.SNAME,B.PJ FROM
(SELECT SID,AVG(SCORE) PJ FROM (SELECT * FROM SC WHERE SCORE<60)A
GROUP BY SID HAVING COUNT(DISTINCT CID)>=2)B
LEFT JOIN STUDENT S
ON S.SID=B.SID
** 16. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息**
思路:找出01课程分数小雨60的学生,降序排列,记为表a
用inner join链接表a与student 表
select s.*,a.score from student s inner join
(select * from sc where cid='01' and score<60 order by score desc) a
on a.sid=s.sid
17. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
思路:用case when 选出各课程的成绩,求平均值,group by sid
select sid,
max(case when cid=01 then score else null end) '01',
max(case when cid=02 then score else null end) '02',
max(case when cid=03 then score else null end) '03',
avg(score) as mean from sc group by sid order by mean desc
18.查询各科成绩最高分、最低分和平均分 以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列:
思路:链接course表和score表,group by cid,用聚合函数min max avg求出最低最高平均值。用case when + sum 进行符合条件的计数
select c.cid,c.cname,
max(sc.score),min(sc.score),avg(sc.score),
sum(case when score>=60 then 1 else 0 end)/count(sc.score) as '及格',
sum(case when score>=70 and score<80 then 1 else 0 end)/count(sc.score) as '中等',
sum(case when score>=80 and score<90 then 1 else 0 end)/count(sc.score) as '优良',
sum(case when score>=90 then 1 else 0 end)/count(sc.score) as '优秀'
from course c join sc on c.cid=sc.cid group by c.cid
19.按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
思路:用窗口函数rank() over(cid)来对各科进行排名,保留名词空缺,即用rank()
而dense_rank()表示连续排序没有名次空缺,row_number()单纯的行号
select *,
rank() over(partition by cid order by score desc) as rank from sc
20.查询学生的总成绩,并进行排名,总分重复时保留名次空缺
思路:group by sid,计算总成绩,用rank() over() 对总成绩进行排名
select sid,sum(score),
rank() over(order by sum(score) desc)
from sc group by sid
21. 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
思路:与上一题类似,把rank() 改成dense_rank()即是不保留名次空缺
22. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
思路:group by 课程cid,case when 筛选各分数段人数
再用分段人数除各科人数即是各分段的百分比
select
cid,
count(case when score<60 then score end)'0-60',
round(count(case when score<60 then score end)/count(score),2)'0-60 %',
count(case when score>60 and score<=70 then score end)'60-70',
round(count(case when score>60 and score<=70 then score end)/count(score),2)'60-70%',
count(case when score>70 and score<=85 then score end)'70-85',
round(count(case when score>70 and score<=85 then score end)/count(score),2)'70-85%',
count(case when score>85 and score<=100 then score end)'85-100',
round(count(case when score>85 and score<=100 then score end)/count(score),2)'85-100%'
from sc
group by cid
23. 查询各科成绩前三名的记录
思路:在sc表中用row_number() over(partition by)求得各科成绩的排名
再与student表内链接
select a.cid,s.sid,a.score,a.rank from student s left join
(select *,row_number() over(partition by cid order by score desc) as rank
from sc) a
on
s.sid=a.sid
where a.rank in (1,2,3)
24.查询每门课程被选修的学生数
思路: 以课程为分组对每门课的学生数量进行计数
再与课程表进行内链接
select c.cid,c.cname,a.cnt from course c inner join
(select *,count(distinct sid) cnt from sc group by cid)a
on c.cid=a.cid
25.查询出只选修两门课程的学生学号和姓名
思路:子查询课程计数为2 的学生id,再与学生表格内链接拼接
select s.sid,s.sname from student s inner join
(select * from sc group by sid having count(distinct cid)=2) a
on a.sid=s.sid
26.查询男生、女生人数
思路:以性别分组,计数
select ssex,count(ssex) from student group by ssex
27.查询名字中含有「风」字的学生信息
思路:where语句筛选+通配符%
select * from student where sname like '%风%'
28.查询同名同性学生名单,并统计同名人数
思路:group by 名字 选出count(sname)>1的记录
select sname,count(sname) from student group by sname having count(sname)>1
结果:
无同名同姓
29.查询 1990 年出生的学生名单
year()函数能把时间戳转换成年份
select * from student where year(sage)=1990
30.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
思路:Group by cid 求平均,主要考察多重排序的写法
select cid,avg(score) from sc group by cid order by avg(score) desc,cid asc
31.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
思路:子表以课程号groupby分组查平均分大于85的同学,内链接学生表输出学生信息
select s.sid,s.sname,a.mean from student s inner join
(select sid,avg(Score) mean from sc group by sid having avg(Score)>85) a
on a.sid=s.sid
32.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
思路:三表链接,再用where进行筛选
select s.sname,sc.score from sc left join course c on sc.cid=c.cid
left join student s on s.sid=sc.sid
where c.cname='数学' and sc.score<60
**33.查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况) **
思路:因为存在没成绩没选课的学生,所以需要用student 为主表,left join 成绩表
select s.sid,s.sname,sc.cid,sc.score from student s left join sc on s.sid=sc.sid
34.查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
思路:用<70筛选出 成绩不符合要求的学生,再用not求补集就是所有成绩均不小于70的学生,最后与student 表格链接
select s.sname,sc.cid,sc.score from sc left join student s on s.sid=sc.sid
where sc.sid not in (select sid from sc where score<70)
35.查询不及格的课程
思路:简单,略
select * from sc where score<60
36.查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
思路:简单,略
select s.sid,s.sname from student s left join sc on s.sid=sc.sid where sc.cid=01 and sc.score>80
结果:
无查询结果
37.求每门课程的学生人数
思路:简单,略
select cid,count(sid) from sc group by cid
38.成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
思路:成绩不重复,所以不用rank 用 limit也行。多个表链接,用张三作为条件筛选出学生,用order by limit 1 找出成绩最高的学生
select s.sid,s.sname,s.sage,s.ssex,sc.score from sc inner join course c on sc.cid=c.cid
inner join teacher t on c.tid=t.tid
inner join student s on s.sid=sc.sid
where t.tname='张三'
order by score desc limit 1
39.成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
思路:(为了更符合题意我把07好学生也改成90分) 成绩有重复,意味着不能用limit了。这里先用max找出张三老师的最高分数,在作为条件进行筛选
select s.sid,s.sname,s.sage,s.ssex,sc.score from sc
inner join course c on sc.cid=c.cid
inner join teacher t on c.tid=t.tid
inner join student s on s.sid=sc.sid where t.tname='张三' and
sc.score in (select max(score) from sc where cid=02)
40.查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
思路: 课程不同,成绩相同,意味着(sid,score)这对属性是一样的,先group by (sid,score)。再group by sid,筛选出计数只有1的即可。
select sid,cid,score from (select * from sc group by sid,score)a
group by sid having count(sid)=1
41.查询每门功成绩最好的前两名
思路:用dense rank() over() 对每门课进行分数排名,选出排名为1,2 的学生
select *,dense_rank() over(partition by cid order by score desc) as rank
from sc where rank in (1,2)
结果:
无
42.统计每门课程的学生选修人数(超过 5 人的课程才统计)
思路:group by cid, count(sid)>5筛选
select cid,count(sid) cnt from sc group by cid
having count(sid)>5 order by cnt desc,cid asc
43.检索至少选修两门课程的学生学号
思路:简单,略
select sid from sc group by sid
having count(cid)>=2
44.查询选修了全部课程的学生信息
思路:group by sid,计数课程数,为全部课程的即符合
select * from student s where sid in (select sid from sc group by sid
having count(cid)=(select count(cid) from course))
45.查询各学生的年龄,只按年份来算
思路:用datediff(date1,date2) 求出天数差,再除365求得年龄
select *,round(datediff('2020-08-01',sage)/365,0) as age from student
46.按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
思路:用函数 timestampdiff(unit,begin,end)来表示未过生日年龄减一
SELECT s.sname,
TIMESTAMPDIFF(year,s.sage,CURRENT_DATE()) AS age,s.sage
FROM student s
47.查询本周过生日的学生
思路:用week函数求出本日期是一年中第几周
SELECT *
from student
where week(sage,1)=week(current_Date(),1)
结果:
无符合
48.查询下周过生日的学生
思路:用week函数求出本日期是一年中第几周
SELECT *
from student
where week(sage,1)=week(current_Date(),1)+1
49.查询本月过生日的学生
思路:与week()类似的month()
select * from student
where month(sage)=month(current_date())
50.查询下月过生日的学生
思路:同理
select * from student
where month(sage)=month(current_date())+1