数据表
--1.学生表
Student(SId,Sname,Sage,Ssex)
--SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别
--2.课程表
Course(CId,Cname,TId)
--CId --课程编号,Cname 课程名称,TId 教师编号
--3.教师表
Teacher(TId,Tname)
--TId 教师编号,Tname 教师姓名
--4.成绩表
SC(SId,CId,score)
--SId 学生编号,CId 课程编号,score 分数
创建测试数据
学生表 Student
create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(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('09' , '张三' , '2017-12-20' , '女');
insert into Student values('10' , '李四' , '2017-12-25' , '女');
insert into Student values('11' , '李四' , '2017-12-30' , '女');
insert into Student values('12' , '赵六' , '2017-01-01' , '女');
insert into Student values('13' , '孙七' , '2018-01-01' , '女');
科目表 Course
create table Course(CId varchar(10),Cname nvarchar(10),TId varchar(10))
insert into Course values('01' , '语文' , '02')
insert into Course values('02' , '数学' , '01')
insert into Course values('03' , '英语' , '03')
教师表 Teacher
create table Teacher(TId varchar(10),Tname varchar(10))
insert into Teacher values('01' , '张三')
insert into Teacher values('02' , '李四')
insert into Teacher values('03' , '王五')
成绩表 SC
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 "课程成绩高的学生的信息及课程分数
select *
from (select SId ,score from sc where sc.CId='01')as t1 , (select SId ,score from sc where sc.CId='02') as t2
where t1.SId=t2.SId
and t1.score>t2.score
1.1 查询同时存在" 01 “课程和” 02 "课程的情况
select *
from (select SId ,score from sc where sc.CId='01')as t1
join (select SId ,score from sc where sc.CId='02') as t2
on t1.SId=t2.SId
1.2 查询存在" 01 “课程但可能不存在” 02 "课程的情况(不存在时显示为 null )
select *
from (select SId ,score from sc where sc.CId='01')as t1
left join (select SId ,score from sc where sc.CId='02') as t2
on t1.SId=t2.SId
1.3 查询不存在" 01 “课程但存在” 02 "课程的情况
思路,要求首先得到选择了02课程的学员,然后剔除掉选择01课程的学员
知识点:子查询,NOT IN
select *
from sc
where sc.SId not in (select SId from sc where sc.CId='01')
and sc.CId='02'
select S.SId, Sname, avg(score)
from Student s
join SC c
on s.`SId`=c.`SId`
group by s.`SId`
HAVING avg(score) >= 60
SELECT DISTINCT s.*
FROM Student s
JOIN SC c
ON s.`SId`=c.`SId`
4.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为null)
SELECT s.SId, s.Sname, count(c.CId), sum(c.score)
FROM Student s
join SC c
on s.`SId`=c.`SId`
group by s.`SId`
select count(*)
from teacher
where teacher.Tname like ('李%’)
SELECT DISTINCT s.*
FROM Student s
JOIN SC sc ON s.SId=sc.SId
JOIN course c ON sc.CId=c.CId
JOIN Teacher t ON t.TId=c.TId
WHERE t.Tname = "张三"
解题思路:首先利用子查询查询course表查询得到共有几门课,按照groupby的方式求课程数加上having小于查询出来的课程的所有学员信息就好
知识点:子查询,groupby,having,join
select s.*
from Student s
left join SC c
on s.`SId`=c.`SId`
group by c.`SId`
having count(c.CId) <(select count(CId) from course)
查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
这里就有一个知识点就是group by有去除重复值的功能,这个其实不难理解,因为group by就是按照单个组分类,可以理解为按照同一类进行切分
SELECT s.*
FROM SC
JOIN Student s
ON SC.`SId`=s.SId
WHERE SC.CId IN (SELECT CId FROM SC WHERE SId='01')
AND SC.`SId` <>'01'
GROUP BY SC.sid;
9.查询和" 01 "号的同学学习的课程完全相同的其他同学的信息
10.查询没学过"张三"老师讲授的任一门课程的学生姓名
解题思路:1先要查询出张三老师的教授课程,2然后利用not in 来找到学生的id
知识点:子查询,not in,多重join
SELECT s.SId, s.Sname
FROM Student s
WHERE SId NOT IN
( SELECT SId
FROM Course c
JOIN Teacher t ON c.`TId`=t.`TId`
JOIN SC ON SC.`CId`=c.`CId`
WHERE t.Tname = "张三")
11.查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
解题思路:题中提到了两门及以上的不及格课程,因此考虑使用Groupby 和 having,题中还提到学生姓名以及平均成绩,考虑到这里还要求出平均成绩,但是平均成绩说明不是很清楚,
知识点:Group by ,having,以及子查询在from子句中的使用
select s.sid, sname, avg(score) avg_score
from sc
join Student s
on sc.sid = s.`sid`
having score < 60
group by sc.sid
having count(sc.cid) >= 2
SELECT s.*
FROM Student s
JOIN SC c
ON s.`sid`=c.`sid`
WHERE cid = 01 AND score < 60
ORDER BY score DESC
解题思路:要按照平均成绩降序排列,则需要使用group by,以及要显示所有的课程信息,那么就需要使用join来实现了
知识点:group by ,子查询,join
SELECT
s.*,
avg_score
FROM
sc AS s
LEFT JOIN
(SELECT
sc.sid ,AVG(sc.score) AS avg_score
FROM
sc
GROUP BY sc.sid
) r
ON s.sid = r.sid
ORDER BY avg_score DESC ;
SELECT
cid AS 课程ID,
COUNT(sid) AS 课程人数,
MAX(score) AS 最高分,
MIN(score) AS 最低分,
AVG(score) AS 平均分,
SUM(及格) / COUNT(sid) AS 及格率,
SUM(中等) / COUNT(sid) AS 中等率,
SUM(优良) / COUNT(sid) AS 优良率,
SUM(优秀) / COUNT(sid) AS 优秀率
FROM
(SELECT
*,
CASE
WHEN score >= 60
THEN 1
ELSE 0
END AS 及格,
CASE
WHEN score >= 70
AND score < 80
THEN 1
ELSE 0
END AS 中等,
CASE
WHEN score >= 80
AND score < 90
THEN 1
ELSE 0
END AS 优良,
CASE
WHEN score >= 90
THEN 1
ELSE 0
END AS 优秀
FROM
sc) a
GROUP BY cid
ORDER BY COUNT(sid) DESC,
cid ;
15.按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
自交:用sc中的score和自己进行对比,来计算“比当前分数高的分数有几个”。
select a.cid, a.sid, a.score, count(b.score)+1 as rank
from sc as a
left join sc as b
on a.score<b.score and a.cid = b.cid
group by a.cid, a.sid,a.score
order by a.cid, rank ASC;
15.1 按各科成绩进行排序,并显示排名, Score 重复时合并名次
这里主要学习一下使用变量。在SQL里面变量用@来标识。
set @crank=0;
select q.sid, total, @crank := @crank +1 as rank from(
select sc.sid, sum(sc.score) as total from sc
group by sc.sid
order by total desc)q;
SELECT
a.*,
@rank := @rank + 1 AS rank
FROM
(SELECT
sid,
SUM(score)
FROM
sc
GROUP BY sid
ORDER BY SUM(score) DESC) a,
(SELECT
@rank := 0) b ;
16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
SELECT
a.*,
CASE
WHEN @fscore = a.sumscore
THEN @rank
WHEN @fscore := a.sumscore
THEN @rank := @rank + 1
END AS 排名
FROM
(SELECT
sc.sid,
SUM(score) AS sumscore
FROM
sc
GROUP BY sid
ORDER BY SUM(score) DESC) AS a,
(SELECT
@rank := 0,
@fscore := NULL) AS t ;
SELECT
sc.cid AS 课程编号,
cname AS 课程名称,
SUM(
CASE
WHEN score >= 0
AND score <= 60
THEN 1
ELSE 0
END
) AS '[60-0]',
SUM(
CASE
WHEN score >= 0
AND score <= 60
THEN 1
ELSE 0
END
) / COUNT(sid) AS '[60-0]百分比',
SUM(
CASE
WHEN score >= 60
AND score <= 70
THEN 1
ELSE 0
END
) AS '[70-60]',
SUM(
CASE
WHEN score >= 60
AND score <= 70
THEN 1
ELSE 0
END
) / COUNT(sid) AS '[70-60]百分比',
SUM(
CASE
WHEN score >= 70
AND score <= 85
THEN 1
ELSE 0
END
) AS '[85-70]',
SUM(
CASE
WHEN score >= 70
AND score <= 85
THEN 1
ELSE 0
END
) / COUNT(sid) AS '[85-70]百分比',
SUM(
CASE
WHEN score >= 85
AND score <= 100
THEN 1
ELSE 0
END
) AS '[100-85]',
SUM(
CASE
WHEN score >= 85
AND score <= 100
THEN 1
ELSE 0
END
) / COUNT(sid) AS '[100-85]百分比'
FROM
sc
JOIN course
ON sc.cid = course.cid
GROUP BY sc.cid,
cname ;
思路:前三名转化为若大于此成绩的数量少于3即为前三名。
SELECT a.*,COUNT(b.score) +1 AS ranking
FROM SC AS a LEFT JOIN SC AS b
ON a.cid = b.cid AND a.score<b.score
GROUP BY a.cid, a.sid
HAVING ranking <= 3
ORDER BY a.cid, ranking;
SELECT cid, COUNT(sid)
FROM SC
GROUP BY cid
SELECT s.sname, s.sid
FROM student s
JOIN SC c
ON s.sid=c.sid
GROUP BY c.`sid`
HAVING COUNT(c.cid) = 2
21.查询男生、女生人数
select ssex, count(ssex)
from student
group by ssex
select *
from student
where student.Sname like '%风%'
23.查询同名同性学生名单,并统计同名人数
SELECT sname, COUNT(sname) "同名人数", ssex , COUNT(ssex) "同性人数"
FROM student
GROUP BY sname, ssex
HAVING "同名人数">1 AND "同性人数">1
24.查询 1990 年出生的学生名单
SELECT s.*
FROM student s
WHERE sage LIKE "1990%"
25.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT sc.*, AVG(score)
FROM sc
GROUP BY cid
ORDER BY AVG(score) DESC, cid ASC
26.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩 !!!面经遇到过
解题思路:按照学生id分组,然后求平均分,然后用having语句判断平均分大于等于85,又因为要查询学生姓名因此可以使用join,或者直接使用笛卡尔积,但是笛卡尔积对于数据量比较大的时候不宜使用
SELECT s.sname, s.sid, AVG(score)
FROM student s
JOIN sc c
ON s.sid=c.sid
GROUP BY s.`sid`
HAVING AVG(score) >= 85
思路:多重join的使用
SELECT ss.sname, score
FROM sc s
JOIN course c
ON c.`cid`=s.`cid`
JOIN student ss
ON ss.sid=s.`sid`
WHERE c.cname="数学" AND s.score < 60
思路:外连接
SELECT s.*, sc.*
FROM student s
LEFT JOIN sc
ON s.`sid`=sc.`sid`
SELECT
sname,
sc.cid,
score
FROM
sc
INNER JOIN student AS s
ON sc.sid = s.sid
AND score > 70 ;
30.查询存在不及格的课程
SELECT DISTINCT cid,score
FROM sc
WHERE score < 60 ;
31.查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
SELECT s.sname, s.sid
FROM student s
JOIN sc c
ON s.sid = c.`sid`
WHERE cid = 01 AND c.score >= 80
SELECT cid, COUNT(sid) 人数
FROM sc
GROUP BY cid
解题思路:这题首先要找到张三老师所授课程,然后找到选择这门课程的学生,在成绩按照从大到小的顺序排列,然后只取最高的成绩,当然还需要使用子查询
SELECT
s.*,
score
FROM
student AS s
INNER JOIN sc
ON s.sid = sc.sid
WHERE sc.cid =
(SELECT
cid
FROM
teacher AS t
INNER JOIN course AS c
ON t.tid = c.tid
AND tname = '张三')
ORDER BY score DESC
LIMIT 1 ;
解题思路:有重复成绩,我们就选择一个最大成绩然后使用子查询,让成绩在各科成绩的最大值里面做筛选
SELECT
student.*,
sc.cid,
score
FROM
student
INNER JOIN sc
ON student.sid = sc.sid
JOIN course
ON sc.cid = course.cid
JOIN teacher
ON course.tid = teacher.tid
WHERE tname = '张三'
AND score IN
(SELECT
MAX(score)
FROM
sc
INNER JOIN course
ON sc.cid = course.cid
JOIN teacher
ON course.tid = teacher.tid
WHERE tname = '张三') ;
查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
解题思路:首先join两张表,然后做筛选1成绩相同,2课程id不相同
select distinct a.*
from sc a
join sc b
on a.sid = b.sid
where a.score = b.score
and a.cid <> b.cid
36.查询每门功成绩最好的前两名
解题思路:这题和前面有一题有很相似的地方,就是找到大于某个成绩只有两人就是前两名
SELECT
*
FROM
sc
WHERE
(SELECT
COUNT(*)
FROM
sc AS a
WHERE sc.cid = a.cid
AND sc.score < a.score) < 2
ORDER BY cid ASC,
sc.score DESC ;
37.统计每门课程的学生选修人数(超过 5 人的课程才统计)
select cid, count(sid)
from sc
group by cid
having COUNT(sid)>=5
38.检索至少选修两门课程的学生学号
select sid, COUNT(cid)
from sc
group by sid
having count(cid)>=2
SELECT
s.*
FROM
sc
INNER JOIN student AS s
ON sc.sid = s.sid
WHERE cid =
(SELECT
COUNT(*)
FROM
course) ;
40.查询各学生的年龄,只按年份来算
SELECT sname, YEAR(NOW())-YEAR(sage) 年纪
FROM student
select student.SId as 学生编号,student.Sname as 学生姓名,TIMESTAMPDIFF(YEAR,student.Sage,CURDATE()) as 学生年龄
from student
42.查询本周过生日的学生
select sname
from student
where week(sage) = week(now())
select sname
from student
where week(sage) = week(now())+1
44.查询本月过生日的学生
SELECT
sname,
sage
FROM
student
WHERE MONTH(sage) = MONTH(NOW());
45.查询下月过生日的学生
SELECT
sname,
sage
FROM
student
WHERE MONTH(sage) = MONTH(NOW()) + 1;