sql50题

文章转自:https://zhuanlan.zhihu.com/p/38354000

题目

已知有如下4张表:

学生表:

Student(s_id,s_name,s_birth,s_sex) –学生编号,学生姓名, 出生年月,学生性别

课程表:

Course(c_id,c_name,t_id) – –课程编号, 课程名称, 教师编号

教师表:

Teacher(t_id,t_name) –教师编号,教师姓名

成绩表:

Score(s_id,c_id,s_s_score) –学生编号,课程编号,分数

根据以上信息按照下面要求写出对应的SQL语句。

问题
  1. 查询姓“张”的老师的个数

  2. 查询含“风”的学生名单

  3. 1990年出生的学生名单(注:Student表中s_birth列的类型是datetime)

  4. 查询课程编号为“01”的总成绩

  5. 查询选了课程的学生人数

  6. 查询各科成绩最高和最低的分: 以如下的形式显示:课程ID,最高分,最低分

  7. 查询每门课程被选修的学生数

  8. 查询男生、女生人数

  9. 查询平均成绩大于60分的学生的学号和平均成绩

  10. 查询至少选修两门课程的学生学号

  11. 查询两门以上不及格课程的同学的学号及其平均成绩

  12. 查询同名同性学生名单并统计同名人数

  13. 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列

  14. 查询不及格的课程并按课程号从大到小排列

  15. 检索课程编号为“01”且分数小于60的学生学号,结果按按分数降序排列

  16. 统计每门课程的学生选修人数(超过5人的课程才统计)。

    要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序

  17. 查询所有课程成绩小于60分的学生的学号、姓名

  18. 查询没有学全所有课的学生的学号、姓名

  19. 查询出只选修了两门课程的全部学生的学号和姓名

  20. 查询课程编号为03且课程成绩在80分以上的学生的学号和姓名

  21. 查询课程编号为“001”的课程比“002”的课程成绩高的所有学生的学号

  22. 按平均成绩从高到低,按如下形式显示:学生ID,有效课程数,有效平均分

  23. 使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计各分数段人数:课程ID和课程名称

  24. 查询出每门课程的及格人数和不及格人数

  25. 查询出每门课程的及格百分数

  26. 查询至少有一门课与学号为“01”的学生所学课程相同的学生的学号和姓名

  27. 查询和“01”号同学所学课程完全相同的其他同学的学号

  28. 把“SCORE”表中“张三”老师教的课的成绩都更改为此课程的平均成绩

  29. 查询和“02”号的同学学习的课程完全相同的其他同学学号和姓名

  30. 按各科平均成绩从低到高和及格率的百分数从高到低排列,以如下形式显示:

    课程号,课程名平均成绩,及格百分数

  31. 查询不同老师所教不同课程平均分从高到低显示

  32. 查询学生平均成绩及其名次

  33. 查询各科成绩前三名的记录(不考虑成绩并列情况)

  34. 查询每门课程成绩最好的前两名

  35. 查询所有学生的学号、姓名、选课数、总成绩

  36. 查询平均成绩大于85的所有学生的学号、姓名和平均成绩

  37. 查询学过编号为“01”的课程并且也学过编号为“02”的课程的学生的学号、姓名

  38. 查询各个课程及相应的选修人数

  39. 查询有2门不同课程成绩相同的学生的学号、课程号、学生成绩

  40. 查询选修了全部课程的学生信息

  41. 查询课程名称为“数学”且分数低于60的学生姓名和分数

  42. 查询所有学生的选课情况

  43. 查询任何一门课程成绩在70分以上的姓名、课程名称和分数

  44. 查询没学过“张三”老师课的学生的学号、姓名

  45. 查询学过“张三”老师所教的所有课的同学的学号、姓名

  46. 查询选修“张三”老师所授课程的学生中成绩最高的学生姓名及其成绩

  47. 查询没学过“张三”老师讲授的任一门课程的学生姓名

  48. 删除学习“张三”老师课的SC表记录

  49. 删除学生编号为“02”的课程编号为“01”的成绩

  50. 向SC表中插入一些记录这些记录要求符合以下条件:没有上过编号为“003”课程的学生的学号、编号为002的课程的平均成绩

分析

​ 这些题考察SQL的编写能力,对于这类型的题目,需要你先把4张表之间的关联关系搞清楚了,最好的办法是自己在草稿纸上画出关联图,然后再编写对应的SQL语句就比较容易了。下图是我画的这4张表的关系图,可以看出它们之间是通过哪些外键关联起来的:

为了演示题目的运行过程,我们先按下面语句在navicat中创建表

-- 学生表
CREATE TABLE Student(
s_id VARCHAR(20),
s_name VARCHAR(20) NOT NULL DEFAULT '',
s_birth VARCHAR(20) NOT NULL DEFAULT '',
s_sex VARCHAR(10) NOT NULL DEFAULT '',
PRIMARY KEY(s_id)
);

-- 课程表
CREATE TABLE Course(
c_id VARCHAR(20),
c_name VARCHAR(20) NOT NULL DEFAULT '',
t_id VARCHAR(20) NOT NULL,
PRIMARY KEY(c_id)
);

-- 教师表
CREATE TABLE Teacher(
t_id VARCHAR(20),
t_name VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY(t_id)
);

-- 成绩表
CREATE TABLE `Score`(
s_id VARCHAR(20),
c_id VARCHAR(20),
s_score INT(3),
PRIMARY KEY(s_id,c_id)
);

在表中插入数据:

-- 插入学生表测试数据
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' , '女');

-- 课程表测试数据
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');

-- 教师表测试数据
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');

-- 成绩表测试数据
insert into Score values('01' , '01' , 80);
insert into Score values('01' , '02' , 90);
insert into Score values('01' , '03' , 99);
insert into Score values('02' , '01' , 70);
insert into Score values('02' , '02' , 60);
insert into Score values('02' , '03' , 80);
insert into Score values('03' , '01' , 80);
insert into Score values('03' , '02' , 80);
insert into Score values('03' , '03' , 80);
insert into Score values('04' , '01' , 50);
insert into Score values('04' , '02' , 30);
insert into Score values('04' , '03' , 20);
insert into Score values('05' , '01' , 76);
insert into Score values('05' , '02' , 87);
insert into Score values('06' , '01' , 31);
insert into Score values('06' , '03' , 34);
insert into Score values('07' , '02' , 89);
insert into Score values('07' , '03' , 98);

参考答案
# 1.查询姓“张”的老师的个数 
#【考察知识点】考察模糊查询
select count(*) from teacher where t_name like "张%";
# 2. 查询含“风”的学生名单
select * from Student where s_name like '%风%';
# 3. 1990年出生的学生名单(注:Student表中s_birth列的类型是datetime)
#【考察知识点】日期类型
select * from student where s_birth like'1990%';
select * from student where year(s_birth)=1990;
# 4.查询课程编号为“02”的总成绩
#【考察知识点】聚合函数(求和sum)
select sum(s_score) from score where c_id='02';
# 5.查询选了课程的学生人数
select count(distinct s_id) as 学生人数 from score;
# 6.查询各科成绩最高和最低的分: 以如下的形式显示:课程ID,最高分,最低分
#【考察知识点】分组(group),聚合函数(最大值max,最小值min)
select c_id,max(s_score),min(s_score)from score group by c_id;
# 7.查询每门课程被选修的学生数
select c_id,count(s_id) from score group by c_id; 
# 8.男生、女生人数
# 察知识点】分组(group),聚合函数(计数count)
select s_sex,count(*) from student group by s_sex;
# 9.查询平均成绩大于60分的学生的学号和平均成绩
# 【考察知识点】分组(group),having (对分组结果按条件过滤)
select s_id,avg(s_score) from score
group by s_id 
having avg(s_score)>60;
# 10.查询至少选修两门课程的学生学号
select s_id from score 
group by s_id
having count(c_id)>=2;
# 11.查询两门以上不及格课程的同学的学号及其平均成绩
select s_id,avg(s_score) from score 
where s_score < 60
group by s_id
having count(c_id)>=2;
# 12.查询同名同性学生名单并统计同名人数
select s_name,count(*) from student
group by s_name 
having count(*)>1;
# 13.每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
# 【考察知识点】分组(group),排序
select c_id,avg(s_score) from score 
group by c_id 
order by avg(s_score),c_id desc;
# 14.查询不及格的课程并按课程号从大到小排列
# 察知识点】分组(group),排序
select c_id,s_score from score
where s_score<60
order by c_id desc; 
# 15.检索课程编号为“01”且分数小于60的学生学号,结果按按分数降序排列
select s_id from score
where c_id=01 and s_score < 60
order by s_score desc
# 16.统计每门课程的学生选修人数(超过5人的课程才统计)。
	# 要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序
#【考察知识点】分组(group),排序(order by)
select c_id,count(s_id) from score group by c_id
having count(s_id)>5
order by count(s_id) desc,c_id
# 17.查询所有课程成绩小于60分的学生的学号、姓名
#【考察知识点】谓词(in)
select s_id,s_name from student
where s_id in (select s_id from score where s_score<60)
# 18.查询没有学全所有课的学生的学号、姓名
#【考察知识点】谓词(in),子查询
select s_id,s_name from student
where s_id in (select s_id from score group by s_id 
having count(c_id)<(select count(c_id) from course))
# 19.查询出只选修了两门课程的全部学生的学号和姓名
select s_id,s_name from student
where s_id in (select s_id from score group by s_id
having count(c_id)=2)
# 20.查询课程编号为03且课程成绩在80分以上的学生的学号和姓名
select s_id,s_name from student
where s_id in (select s_id from score where s_score>80 and c_id=03)
# 联结
# 21.查询课程编号为“001”的课程比“002”的课程成绩高的所有学生的学号
#【考察知识点】联结

#【解题思路】联结。首先查询课程编号分别为001和002的所有学生的学号及其分数作为内嵌视图A和B,然后将A和B通过学号关联,过滤条件就是A的分数大于B的分数,最终SQL如下:
select a.s_id 
from (select * from score where c_id=01) as a
join (select * from score where c_id=02) as b
on a.s_id=b.s_id where a.s_score>b.s_score;
# 22.按平均成绩从高到低,按如下形式显示:学生ID,有效课程数,有效平均分
select s_id as '学生ID',count(c_id) as '有效课程数',avg(s_score)as '平均分' from score
group by s_id 
order by avg(s_score) desc;
# 23.使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计各分数段人数:课程ID和课程名称
# 【解题思路】考察case语句,分段统计的题目都是这个套路
select a.c_id as '课程ID',c_name as '课程名称',
sum(case when s_score between 85 and 100 then 1 else 0 end)as '[100,85]',
sum(case when s_score >=70 and s_score<85 then 1 else 0 end)as '[85,70]',
sum(case when s_score >=60 and s_score<70 then 1 else 0 end)as '[70,60]',
sum(case when s_score < 60 then 1 else 0 end) as '[<60]'
from score a join course b on a.c_id=b.c_id
group by a.c_id,c_name
# 24. 查询出每门课程的及格人数和不及格人数
select c_id,
sum(case when s_score >= 60 then 1 else 0 end) as '及格人数',
sum(case when s_score < 60 then 1 else 0 end) as '不及格人数'
from score group by c_id;
# 25.查询出每门课程的及格百分数
select c_id,(及格人数/总人数)*100 as '及格百分数' from
(select c_id,
sum(case when s_score >= 60 then 1 else 0 end) as '及格人数',
sum(case when s_score < 60 then 1 else 0 end) as '不及格人数',
count(s_id) as '总人数'
from score group by c_id) as per
# 26. 查询至少有一门课与学号为“01”的学生所学课程相同的学生的学号和姓名
# 【解题思路】联结。首先找出学号为01的学生学习过的课程,然后根据这些课程号就可以找到有哪些学生学习过部分01学生学习过的课程
select distinct a.s_id,a.s_name 
from student a join score b on a.s_id=b.s_id
where c_id in
(select c_id from score where s_id=01)
and a.s_id <> 01;
# 27.查询和“01”号同学所学课程完全相同的其他同学的学号
#【解题思路】首先找出学号为001的学生学习过的课程,然后根据这些课程号和所学课程总数就可以找到有哪些同学学习过和他一样的课程
select s_id from score
where c_id in 
(select c_id from score where s_id=01)
and s_id <> 01
group by s_id
having count(c_id)=(select count(c_id) from score where s_id=01)
# 28.把“SCORE”表中“张三”老师教的课的成绩都更改为此课程的平均成绩
#【解题思路】考察数据库更改操作。首先找到张三老师教过哪些课程及其课程的平均成绩,然后根据课程号关联成绩表进行更新
# update 表名 set 列1=值1,列2=值2... where 条件
update score as a join
(select avg(s_score)as t,score.c_id from score
join course on score.c_id=course.c_id
join teacher on course.t_id=teacher.t_id
where t_name='张三') as b # 查出他的课程与平均成绩
on a.c_id=b.c_id
set a.s_score=b.t
# 29.查询和“02”号的同学学习的课程完全相同的其他同学学号和姓名
select a.s_id,a.s_name
from student a join score b on a.s_id=b.s_id
where c_id in (select c_id from score where s_id=02)
and a.s_id <> 02
group by a.s_id
having count(c_id)=(select count(c_id) from score where s_id=02)

# 30.按各科平均成绩从低到高和及格率的百分数从高到低排列,以如下形式显示: 课程号,课程名平均成绩,及格百分数
/*
分析思路:
第1步,分析要求的字段在哪个表里可以得到:
课程号(课程表Course的 c_id) ,课程名(课程表 Course的 c_name),
平均成绩 (成绩博表Score 的s_score),
及格百分数(这个待求)
*/
-- 第2步,获取课程号,课程名
select c_id as '课程号', c_name as '课程名' from course
-- 第3步,获取平均成绩
select avg(s_score) as '平均成绩' from score group by c_id
-- 第4步,上面的第2步和第3步两表通过课程号(c_id)联结,可以得到课程号、课程名、平均成绩
select c.c_id as '课程号', c.c_name as '课程名', avg(s.s_score) as '平均成绩'
from course c join score s
on c.c_id = s.c_id
group by c.c_id
/*
经过前面步骤,现在只剩“及格百分数”未计算出来。
计算百分数的通用方法:
根据相应条件抽出相应count数(myCount)
抽出总count数(totalCount)
计算百分比:myCount / totalCount * 100

每门课程的及格人数=该课程的及格人数/该课程的总人数
*/

-- 第1步,查询出每门课程的及格人数和不及格人数
select c_id ,
sum(case when s_score>=60 then 1 else 0 end) as '及格人数',
sum(case when s_score<60 then 1 else 0 end) as '不及格人数',
count(*) as '该课程总人数' 
from score
group by c_id

-- 基于上面的结果,来继续改造,就可以得出每门课程的及格百分数=及格人数 / 该课程总人数
select c_id, (及格人数/该课程总人数)*100 as '及格百分数'
from 
(select c_id ,
sum(case when s_score>=60 then 1 else 0 end) as '及格人数',
sum(case when s_score<60 then 1 else 0 end) as '不及格人数',
count(*) as '该课程总人数' 
from score
group by c_id ) as per

/*
前面几部分我们分别求出了题目要求的分析结果,现在可以把前面的sql语句和并在一起了
下面的sql合并结果,每个子查询都是前面的一部分sql,可以对照看下
*/
select one.c_id as '课程号',one.c_name as '课程名',one.avg as '平均成绩',two.per as '及格百分数'
FROM
(select c.c_id, c.c_name, avg(s.s_score) as 'avg'
from course c join score s
on c.c_id = s.c_id
group by c.c_id) as one
join
(select c_id, (及格人数/该课程总人数)*100 as 'per'
from 
(select c_id ,
sum(case when s_score>=60 then 1 else 0 end) as '及格人数',
sum(case when s_score<60 then 1 else 0 end) as '不及格人数',
count(*) as '该课程总人数' 
from score
group by c_id ) as per) as two 
on one.c_id=two.c_id

# 31.查询不同老师所教不同课程平均分从高到低显示
# 【考察知识点】三表联结
select two.t_name as '姓名',two.c_name as '课程',one.avg as '平均成绩'
from
(select c_id,avg(s_score) as 'avg' from score GROUP BY c_id
) as one
join 
(select t.t_name,c.c_name,c.c_id
from teacher t join course c on t.t_id = c.t_id) as two
on one.c_id = two.c_id ORDER BY one.avg desc
# 32 查询学生平均成绩及其名次
# 算出在所有同学中有几个同学的平均分高于某个ID,然后+1,就是名次
SELECT s_id as '学号',平均成绩,
      (SELECT COUNT(*) FROM(SELECT s_id,AVG(s_score)AS '平均成绩'
                            FROM score GROUP BY s_id)AS b 
       WHERE b.平均成绩>a.平均成绩)+1 as '名次'
FROM (select s_id,avg(s_score) as 平均成绩 from score group by s_id)AS a
order by 平均成绩 desc;
# 33 查询每门课程成绩最好的前两名
SELECT a.c_id as 课程号,c_name as 课程名称,s_name as 姓名,b.s_score as chengji  FROM 
Course a join Score b on a.c_id=b.c_id
join Student c on c.s_id=b.s_id
WHERE (SELECT COUNT(*) FROM Score d WHERE a.c_id=d.c_id AND b.s_score<d.s_score)<=1
ORDER BY a.c_id ASC,b.s_score DESC

# 34.查询所有学生的学号、姓名、选课数、总成绩
select a.s_id as '学号',a.s_name as '姓名',count(b.c_id) as '选课数',sum(b.s_score) as '总分'
from student a join score b on a.s_id=b.s_id GROUP BY b.s_id
# 35.查询课程名称为“英语”且分数低于60的学生姓名和分数
select s_name,s_score from 
student join score on student.s_id=score.s_id join course on score.c_id = course.c_id
where c_name='英语' and s_score<60
# 36. 删除学习“张三”老师课的SC表记录
delete from score
where c_id in 
(select c_id from course a join teacher b on a.t_id=b.t_id where t_name='张三' )

  • 11
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值