SQL语句
- 1. 四个表:course、score、student、teacher
- 2. SQL的题
- 2.1 查询姓“猴”的学生名单
- 2.2 查询课程编号为“2”的总成绩
- 2.3 查询选了课程的学生人数
- 2.4 查询各科成绩最高和最低的分, 以如下的形式显示:课程号,最高分,最低分
- 2.5 查询每门课程被选修的学生数
- 2.6 查询男生、女生人数
- 2.7 查询平均成绩大于60分学生的学号和平均成绩
- 2.8 查询选修大于两门课程的学生学号
- 2.9 查询同名同性学生名单并统计同名人数
- 2.10 查询分数少于75的课程以及分数,并按课程号从大到小排列
- 2.11 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
- 2.12 检索课程编号为“4”且分数小于等于90的学生学号,分数,结果按按分数降序排列
- 2.13 统计每门课程的学生选修人数(超过2人的课程才统计)
- 3. 复杂查询
- 4. topN问题
- 5. 多表查询
student表的数据如下:
1. 四个表:course、score、student、teacher
1)向学生表里添加数据
添加数据的sql
insert into student(student_id,name,date,sex)
values('5' , '猴子' , '1989-01-01' , '男');
insert into student(student_id,name,date,sex)
values('6' , '小猫' , '1990-12-21' , '女');
insert into student(student_id,name,date,sex)
values('7' , '小小马' , '1991-12-21' , '男');
insert into student(student_id,name,date,sex)
values('8' , '王思' , '1990-05-20' , '男');
2)成绩表(score)
添加数据的sql
insert into score(course_id,student_id,score)
values('4' , '1' , 80);
insert into score(course_id,student_id,score)
values('4' , '2' , 90);
insert into score(course_id,student_id,score)
values('4' , '3' , 99);
insert into score(course_id,student_id,score)
values('5' , '1' , 60);
insert into score(course_id,student_id,score)
values('5' , '3' , 80);
3)课程表
添加数据的sql
insert into course(course_id,name,teacher_id)
values('4' , '音乐' , '4');
insert into course(course_id,name,teacher_id)
values('5' , '美术' , '6');
insert into course(course_id,name,teacher_id)
values('6' , '体育' , '5');
4)教师表里添加数据
添加数据的sql
-- 教师表:添加数据
insert into teacher(teacher_id,name)
values('4' , '新的');
insert into teacher(teacher_id,name)
values('5' , '飞过');
-- 这里的教师姓名是空值(null)
insert into teacher(teacher_id,name)
values('6' , null);
2. SQL的题
2.1 查询姓“猴”的学生名单
-- 查询姓“猴”的学生名单
select * from student WHERE name like '猴%';
-- 查询姓名最后一个字是“猴”的学生
select * from student where name like '%猴';
-- 查询姓名中拥有“猴”的学生名单、
select * from student where name like '%猴%';
2.2 查询课程编号为“2”的总成绩
-- 查询课程编号为“2”的总成绩
select sum(score)
from score
where course_id=2
*
分析思路
select 查询结果 [总成绩:汇总函数sum]
from 从哪张表中查找数据[成绩表score]
where 查询条件 [课程号是2]
*/
2.3 查询选了课程的学生人数
-- 查询选了课程的学生人数
select count(distinct student_id) as studentNum
from score
/*
这个题目翻译成大白话就是:查询有多少人选了课程
select 学号,成绩表里学号有重复值需要去掉
from 从课程表查找score;
(distinct 去重,如果不去重的话,同一个人选了多门课也会叠加上)
*/
2.4 查询各科成绩最高和最低的分, 以如下的形式显示:课程号,最高分,最低分
-- 查询各科成绩最高和最低的分, 以如下的形式显示:课程号,最高分,最低分
select course_id, max(score),min(score)
from score
group by course_id
/*
分析思路
select 查询结果 [课程ID:是课程号的别名,最高分:max(成绩) ,最低分:min(成绩)]
from 从哪张表中查找数据 [成绩表score]
where 查询条件 [没有]
group by 分组 [各科成绩:也就是每门课程的成绩,需要按课程号分组];
*/
2.5 查询每门课程被选修的学生数
-- 查询每门课程被选修的学生数
select course_id,count(student_id)
from score
group by course_id
/*
分析思路
select 查询结果 [课程号,选修该课程的学生数:汇总函数count]
from 从哪张表中查找数据 [成绩表score]
where 查询条件 [没有]
group by 分组 [每门课程:按课程号分组];
*/
2.6 查询男生、女生人数
-- 查询男生、女生人数
select sex,count(sex)
from student
group by sex
/*
分析思路
select 查询结果 [性别,对应性别的人数:汇总函数count]
from 从哪张表中查找数据 [性别在学生表中,所以查找的是学生表student]
where 查询条件 [没有]
group by 分组 [男生、女生人数:按性别分组]
having 对分组结果指定条件 [没有]
order by 对查询结果排序[没有];
*/
2.7 查询平均成绩大于60分学生的学号和平均成绩
-- 查询平均成绩大于60分学生的学号和平均成绩
/*
题目翻译成大白话:
平均成绩:展开来说就是计算每个学生的平均成绩
这里涉及到“每个”就是要分组了
平均成绩大于60分,就是对分组结果指定条件
分析思路
select 查询结果 [学号,平均成绩:汇总函数avg(成绩)]
from 从哪张表中查找数据 [成绩在成绩表中,所以查找的是成绩表score]
where 查询条件 [没有]
group by 分组 [平均成绩:先按学号分组,再计算平均成绩]
having 对分组结果指定条件 [平均成绩大于60分]
*/
select student_id,avg(score)
from score
group by student_id
having avg(score)>60
2.8 查询选修大于两门课程的学生学号
/*
翻译成大白话:
第1步,需要先计算出每个学生选修的课程数据,需要按学号分组
第2步,选修大于两门课程:也就是每个学生选修课程数目>2,对分组结果指定条件
分析思路
select 查询结果 [学号,每个学生选修课程数目:汇总函数count]
from 从哪张表中查找数据 [课程的学生学号:课程表score]
where 查询条件 [选修大于两门课程:需要先计算出每个学生选修了多少门课,
需要用分组,所以这里没有where子句]
group by 分组 [每个学生选修课程数目:按学号分组,然后用汇总函数count计算每个学号都选修了多少门课]
having 对分组结果指定条件 [至少选修两门课程:每个学生选修课程数目>2]
*/
-- 查询选修大于两门课程的学生学号
select student_id,count(course_id)
from score
group by student_id
having count(course_id)>2
2.9 查询同名同性学生名单并统计同名人数
/*
翻译成大白话,问题解析:
1)查找出姓名相同的学生有谁,每个姓名相同学生的人数
查询结果:姓名,人数
条件:怎么算姓名相同?按姓名分组后人数大于等于2,因为同名的人数大于等于2
分析思路
select 查询结果 [姓名,人数:汇总函数count(*)]
from 从哪张表中查找数据 [学生表student]
where 查询条件 [没有]
group by 分组 [姓名相同:按姓名分组]
having 对分组结果指定条件 [姓名相同:count(*)>=2]
order by 对查询结果排序[没有];
*/
SELECT name,count(*) as personNum
from student
GROUP BY name
having count(*)>=2
2.10 查询分数少于75的课程以及分数,并按课程号从大到小排列
/*
分析思路
select 查询结果 [课程号][分数]
from 从哪张表中查找数据 [成绩表score]
where 查询条件 [成绩 <75]
group by 分组 [没有]
having 对分组结果指定条件 [没有]
order by 对查询结果排序[课程号从大到小排列:降序desc];
*/
select course_id,score
from score
where score < 75
order by course_id desc
2.11 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
/*
分析思路
select 查询结果 [课程号,平均成绩:汇总函数avg(成绩)]
from 从哪张表中查找数据 [成绩表score]
where 查询条件 [没有]
group by 分组 [每门课程:按课程号分组]
having 对分组结果指定条件 [没有]
order by 对查询结果排序[按平均成绩升序排序:asc,平均成绩相同时,按课程号降序排列:desc];
*/
select course_id,avg(score) as 平均成绩
from score
group by course_id
order by 平均成绩 asc, course_id desc
2.12 检索课程编号为“4”且分数小于等于90的学生学号,分数,结果按按分数降序排列
/*
分析思路
select 查询结果 []
from 从哪张表中查找数据 [成绩表score]
where 查询条件 [课程编号为“4”且分数小于等于90]
group by 分组 [没有]
having 对分组结果指定条件 []
order by 对查询结果排序[查询结果按按分数降序排列];
*/
select student_id,score
from score
where course_id = 4
and score<=90
ORDER BY score desc
2.13 统计每门课程的学生选修人数(超过2人的课程才统计)
要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序
/*
分析思路
select 查询结果 [要求输出课程号和选修人数]
from 从哪张表中查找数据 []
where 查询条件 []
group by 分组 [每门课程:按课程号分组]
having 对分组结果指定条件 [学生选修人数(超过2人的课程才统计):每门课程学生人数>2]
order by 对查询结果排序[查询结果按人数降序排序,若人数相同,按课程号升序排序];
*/
select course_id,count(student_id) as personNum
from score
group by course_id
HAVING count(student_id)>2
ORDER BY personNum desc,course_id asc
3. 复杂查询
3.1 查询存在不及格课程的同学的学号及其平均成绩
/*
分析思路
先分解题目:
1)[不及格课程]限制条件
2)[同学的学号及其平均成绩],也就是每个学生的平均成绩,显示学号,平均成绩
分析过程:
第1步:先查询存在不及格课程的同学的id
第2步:对第一步查询得到的id进行分组,统计
1)不及格课程
2)[存在不及格课程]:课程数目>0
/*
第1步:得到存在不及格课程的同学的id
select 查询结果 [学号]
from 从哪张表中查找数据 [涉及到成绩:成绩表score]
where 查询条件 [score<60]
group by 分组 [每个学生的平均:按学号分组]
having 对分组结果指定条件 [不合格的成绩的数量大于1]
order by 对查询结果排序[没有];
*/
select student_id
from score
where score<60
GROUP BY student_id
HAVING count(score)>0
/*
第2步:对第一步查询得到的id进行分组,统计平均值
select 查询结果 [学号,平均成绩:汇总函数avg(成绩)]
from 从哪张表中查找数据 [涉及到成绩:成绩表score]
group by 分组 [每个学生的平均:按学号分组]
having 对分组结果指定条件 [限制条件:学号 in 第一步出来的学号]
*/
select student_id,avg(score) as 平均成绩
from score
group by student_id
having student_id in
(
select student_id
from score
where score<60
GROUP BY student_id
HAVING count(score)>0
)
3.2 查询所有课程成绩小于等于80分学生的学号、姓名
【知识点】子查询
1.翻译成大白话
1)查询结果:学生学号,姓名
2)查询条件:所有课程成绩 <= 80 的学生,需要从成绩表里查找,用到子查询
第1步,写子查询(所有课程成绩 <= 80 的学生(我们换一个角度来讲,就是不要存在成绩大于80的学生))
select 查询结果[学号]
from 从哪张表中查找数据[成绩表:score]
where 查询条件[成绩 < 80]
group by 分组[没有]
having 对分组结果指定条件[没有]
order by 对查询结果排序[没有]
limit 从查询结果中取出指定行[没有];
select student_id
from score
WHERE score>80
第2步,查询结果:学生学号,姓名,条件是对前面1步查到的学号取反
select 查询结果[学号,姓名]
from 从哪张表中查找数据[学生表:student]
where 查询条件[用到运算符in](这里的in 的前面可以是where也可以是having,两个随便一个都行)
group by 分组[没有]
having 对分组结果指定条件[没有]
order by 对查询结果排序[没有]
limit 从查询结果中取出指定行[没有];
*/
select student_id,name
from student
where student_id not in
(
select student_id
from score
WHERE score>80
)
3.3 查询没有学全所有课的学生的学号、姓名|
select student_id,name
from student
where student_id not in
(
select student_id
from score
GROUP BY student_id
HAVING count(course_id)>(select count(course_id) from course)
)
3.4 查询出选修了四门课程的全部学生的学号和姓名
select student_id,name
from student
where student_id in
(
select student_id
from score
GROUP BY student_id
HAVING count(course_id)=4
)
3.5 2000年前出生的学生名单
/*
查找2000年前出生的学生名单
学生表中出生日期列的类型是date
*/
select student_id,name
from student
where year(date)<2000
4. topN问题
4.0 按课程号分组取成绩最大值所在行的数据
- 我们可以使用分组(group by)和汇总函数得到每个组里的一个值(最大值,最小值,平均值等)。但是无法得到成绩最大值所在行的数据。按照下面的sql语句的话student_id查询出来的数据好像是错的(技术水平不错,暂时无法理解,如果知道并且愿意的话,请你留言一下)
select course_id,max(score) as 各科最大成绩,student_id
from score
group by course_id
select *
from score as a
where score=(
SELECT max(score)
from score as b
where b.course_id=a.course_id
);
这里特意改了一下课程“2”中其中的一个学生分数,发现有两个相同的最大分数也可以查得出来。
4.1 按课程号分组取成绩最小值所在行的数据
同样的使用关联子查询来实现
select *
from score as a
where score=(
SELECT min(score)
from score as b
where b.course_id=a.course_id
);
4.2 查询各科成绩前两名的记录
- 先使用order by子句按成绩降序排序(desc),然后使用limt子句返回topN(对应这个问题返回的成绩前两名)
select * from score where course_id =1
ORDER BY score DESC LIMIT 2
- 使用union all 将每组选出的数据合并到一起
(select * from score where course_id =1
ORDER BY score DESC LIMIT 2)
union all
(select * from score where course_id =2
ORDER BY score DESC LIMIT 2)
union all
(select * from score where course_id =3
ORDER BY score DESC LIMIT 2)
union all
(select * from score where course_id =4
ORDER BY score DESC LIMIT 2)
union all
(select * from score where course_id =5
ORDER BY score DESC LIMIT 2)
不过上面这样我感觉挺麻烦的,需要先知道有哪些课程编号,然后我想通过下面这种方式行不行,结果只返回了最大的两门课程的数据
select * from score where course_id in (select course_id from course)
ORDER BY score DESC LIMIT 2
5. 多表查询
5.1 查询所有学生的学号、姓名、选课数、总成绩
select s.student_id,s.`name`,count(sc.course_id) as 选课数,sum(sc.score) as 总成绩
from student s
left join score sc
on s.student_id=sc.student_id
GROUP BY s.student_id
5.2 查询平均成绩大于70的所有学生的学号、姓名和平均成绩
select s.student_id,s.`name`,AVG(sc.score) as 平均成绩
from student s
left join score sc
on s.student_id=sc.student_id
GROUP BY s.student_id
HAVING avg(sc.score)>70
5.3 查询学生的选课情况:学号,姓名,课程号,课程名称
两种查询的结果都一样
1.
select s.student_id,s.`name`,c.course_id,c.`name`
from student s,score sc,course c
where s.student_id=sc.student_id and
sc.course_id=c.course_id
2.
SELECT s.student_id,s.`name`,c.course_id,c.`name`
from student s
INNER JOIN score sc on s.student_id=sc.student_id
INNER JOIN course c on sc.course_id=c.course_id
5.4 查询出每门课程的及格人数和不及格人数
注意!注意!注意! 我面试的时候,有做过相似要求的题 QAQ
select course_id,
sum(case when score>=60 then 1
else 0
end) as "及格人数",
sum(case when score< 60 then 1
else 0
end) as "不及格人数"
from score
GROUP BY course_id
5.5 使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计:各分数段人数,课程号和课程名称
select c.course_id,c.`name`,
sum(case when score between 85 and 100
then 1 else 0 end) as '[100-85]',
sum(case when score>=75 and score<85
then 1 else 0 end) as '(85-75]',
sum(case when score>=60 and score<75
then 1 else 0 end) as '(75-60]',
sum(case when score<60 then 1 else 0 end) as '[<60]'
from score sc
RIGHT JOIN course c on sc.course_id=c.course_id
GROUP BY sc.course_id,c.`name`
RIGHT JOIN 右连接,不管course里面的数据在score有没有用到,都显示
select c.course_id,c.`name`,
sum(case when score between 85 and 100
then 1 else 0 end) as '[100-85]',
sum(case when score>=75 and score<85
then 1 else 0 end) as '(85-75]',
sum(case when score>=60 and score<75
then 1 else 0 end) as '(75-60]',
sum(case when score<60 then 1 else 0 end) as '[<60]'
from score sc
left JOIN course c on sc.course_id=c.course_id
GROUP BY sc.course_id,c.`name`
left JOIN 左连接,以左边的为主,右边没有用到的不要
5.6 查询课程编号为0003且课程成绩在80分以上的学生的学号和姓名
两种都可:
select s.student_id,s.`name`
from student s,score sc
where s.student_id=sc.student_id and sc.course_id=4 and sc.score>80
select s.student_id,s.`name`
from student s INNER JOIN score sc on s.student_id=sc.student_id
where sc.course_id=4 and sc.score>80
5.7. 行列如何互换
下面是学生的成绩表(表名score,列名:学号、课程号、成绩)
使用sql实现将该表行转列为下面的表结构
//第1步,使用常量列输出目标表的结构
select student_id,'课程号1','课程号2','课程号3','课程号4','课程号5'
from score;
//第2步,使用case表达式,替换常量列为对应的成绩
select student_id,
(case course_id when 1 then score else 0 end)as '课程号1',
(case course_id when 2 then score else 0 end)as '课程号2',
(case course_id when 3 then score else 0 end)as '课程号3',
(case course_id when 4 then score else 0 end)as '课程号4',
(case course_id when 5 then score else 0 end)as '课程号5'
from score
ORDER BY student_id asc
//在这个查询结果中,每一行表示了某个学生某一门课程的成绩。
//比如第一行是'学号1'选修'课程号1'的成绩,而其他两列的'课程号2、3、4、5'成绩为0。
//如下方图所示
//第三步,分组 ,并使用最大值函数max取出下图学生每一个课程的最大值
select student_id,
max(case course_id when 1 then score else 0 end)as '课程号1',
max(case course_id when 2 then score else 0 end)as '课程号2',
max(case course_id when 3 then score else 0 end)as '课程号3'
from score
GROUP BY student_id
参考:https://blog.csdn.net/u010565545/article/details/100785261/