50道MySQL经典练习题

这个是网上流传的50道SQL练习题,最近拿来练习,刚做完,这里把我做的答案给大家做个参考,如有错误,还请告知。

另外,做题的时候先不要看答案(答案不唯一,只要满足要求即可),要有自己的一个思考过程,这样做出来才能达到最好的训练效果。(感觉做这种题是会上瘾的……

我使用的Mysql版本是5.7.19。SQL语句可能会因数据库系统的不同会有少许差异。

这里放上MySQL语法执行的先后顺序

7:SELECT 查询列表
1:FROM 表
2:连接类型 JOIN 表2
3:ON 连接条件
4:WHERE 筛选条件
5:GROUP BY 分组
6:HAVING 分组后的筛选
8:ORDER BY 排序列表
9:LIMIT 偏移,条目数;

123:先找到表
456:在找到的表中筛选条件
7:把筛选后的数据取出来,进行展示(也就是我们看到的数据)
89:对数据排序,提取

数据表说明

  • 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 分数

创建测试数据

1.学生表

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' , '女');

2.课程表

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')

3.教师表

create table Teacher(TId varchar(10),Tname varchar(10))
insert into Teacher values('01' , '张三')
insert into Teacher values('02' , '李四')
insert into Teacher values('03' , '王五')

4.成绩表

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 "课程成绩高的学生的信息及课程分数

1.1 查询同时存在" 01 “课程和” 02 "课程的情况

1.2 查询存在" 01 “课程但可能不存在” 02 "课程的情况(不存在时显示为 null )

1.3 查询不存在" 01 “课程但存在” 02 "课程的情况

  1. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩

  2. 查询在 SC 表存在成绩的学生信息

  3. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )

4.1 查有成绩的学生信息

  1. 查询「李」姓老师的数量

  2. 查询学过「张三」老师授课的同学的信息

  3. 查询没有学全所有课程的同学的信息

  4. 查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息

  5. 查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息

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

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

  8. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息

  9. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

  10. 查询各科成绩最高分、最低分和平均分:

以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率

及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90

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

  1. 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺

15.1 按各科成绩进行排序,并显示排名, Score 重复时合并名次

  1. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺

16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺

  1. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比

  2. 查询各科成绩前三名的记录

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

  4. 查询出只选修两门课程的学生学号和姓名

  5. 查询男生、女生人数

  6. 查询名字中含有「风」字的学生信息

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

  8. 查询 1990 年出生的学生名单

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

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

  11. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数

  12. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)

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

  14. 查询不及格的课程

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

  16. 求每门课程的学生人数

  17. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩

  18. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩

  19. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩

  20. 查询每门功成绩最好的前两名

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

  22. 检索至少选修两门课程的学生学号

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

  24. 查询各学生的年龄,只按年份来算

  25. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一

  26. 查询本周过生日的学生

  27. 查询下周过生日的学生

  28. 查询本月过生日的学生

  29. 查询下月过生日的学生

参考答案

由于本人sql水平不高,写的代码可能会比较粗糙,大家将就着看,如有更好的写法或者本有有错误的,也请告知,希望能跟大家共同学习,感谢。
另外,写的时候,有的题目会写有一些想法写下来,供大家参考学习。

1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数
# 把01,02课程的成绩提取出来,并进行表连接,为了后面的加减方便
# 通过成绩的加减,得到对应的学号

SELECT class1.*,s2
FROM (SELECT student.*,score AS s1 FROM sc JOIN course AS cou ON cou.CId = sc.`CId`JOIN student ON sc.`SId`=student.`SId`WHERE cou.CId = '01') AS class1
JOIN (SELECT student.*,score AS s2 FROM sc JOIN course AS cou ON cou.CId = sc.`CId`JOIN student ON sc.`SId`=student.`SId`WHERE cou.CId = '02') AS class2
ON class1.SId = class2.SId
WHERE s1 > s2;

1.1 查询同时存在" 01 "课程和" 02 "课程的情况
# 也是先把01,02课程分别提取出来,做合并,然后从中找到学号相同的情况
SELECT class1.SId,s1,s2
FROM (SELECT SId,score AS s1 FROM sc WHERE sc.`CId`='01') AS class1,
	     (SELECT SId,score AS s2 FROM sc WHERE sc.`CId`='02') AS class2
WHERE class1.SId = class2.SId;

1.2 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 NULL )
# 把01,02课程分别提取出来,然后通过左右链接,以01表为准进行条件查询
SELECT *
FROM (SELECT SId,score FROM sc WHERE sc.`CId`='01') AS class1 
LEFT JOIN (SELECT SId,score FROM sc WHERE sc.`CId`='02') AS class2 
ON class1.SId=class2.SId;

1.3 查询不存在" 01 "课程但存在" 02 "课程的情况
#同上
SELECT *
FROM (SELECT SId,score FROM sc WHERE sc.`CId`='01') AS class1 
RIGHT JOIN (SELECT SId,score FROM sc WHERE sc.`CId`='02') AS class2 
ON class1.SId=class2.SId;


2. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
# 正常按照要求编写,用到SQL中的分组和分组条件

SELECT student.`SId`,student.`Sname`,AVG(score) AS 平均成绩
FROM student 
JOIN sc
ON student.`SId`=sc.`SId`
GROUP BY student.`SId`
HAVING AVG(score) >=60;

3. 查询在 SC 表存在成绩的学生信息
# 条件筛选
SELECT student.*
FROM student
LEFT JOIN sc
ON student.`SId` = sc.`SId`
WHERE sc.`SId` IS NOT NULL
GROUP BY student.`SId`;

4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 NULL )
#利用左右链接,以学生表为主表
SELECT s.`SId`,s.Sname,COUNT(c.CId),SUM(score)
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
LEFT JOIN course AS c
ON sc.`CId` = c.CId
GROUP BY s.SId;


4.1 查有成绩的学生信息
# 以学生表为主表,然后进行NULL值的筛选
SELECT  s.*
FROM Student AS s
LEFT JOIN sc
ON s.SId= sc.`SId`
WHERE sc.score IS NOT NULL
GROUP BY s.SId;

5. 查询「李」姓老师的数量
#利用LIKE进行匹配查询
SELECT COUNT(*)
FROM Teacher AS t
WHERE t.Tname LIKE '李%';

6. 查询学过「张三」老师授课的同学的信息
# 应用子查询,将张三老师的CId求出来,再与其他表对应
SELECT s.*
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
WHERE sc.CId = (

	SELECT c.CId
	FROM Teacher AS t
	LEFT JOIN course AS c
	ON t.TId = c.TId
	WHERE t.Tname = '张三'
);

7. 查询没有学全所有课程的同学的信息 
# 应用count()数量进行筛选
SELECT s.*,COUNT(sc.`CId` )
FROM Student AS s
LEFT JOIN sc
ON s.SId =sc.`SId`
GROUP BY s.SId
HAVING COUNT(sc.`CId` )<3;

8. 查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息 
# 至少有一个,应用IN来解决
SELECT DISTINCT s.*
FROM student AS s
JOIN sc
ON s.SId = sc.`SId`
WHERE CId IN(
SELECT sc.`CId`
FROM sc
WHERE sc.`SId` = '01');


9. 查询和" 01 "号的同学学习的课程完全相同的其他同学的信息 
"这个题的答案和想法有问题,目前还没有比较好的解决方案,如果以后想出来会补上 "
#这里我想的处理思路是这样的,首先对课程进行1234……的编码
#然后把跟01课程数相同的同学提取出来,保证课程的数量相同
#再把课程编码求和,以此保证课程完全相同

#对课程排序
SELECT CId,@r:=@r+1 AS rank
FROM course,(SELECT @r:=0) AS r;

#查看01同学的课程编码数求和
SELECT SUM(rank)  AS 课程编码数求和
FROM sc
LEFT JOIN 
(
	SELECT CId,@r:=@r+1 AS rank
	FROM course,(SELECT @r:=0) AS r
) AS cr
ON sc.`CId` = cr.CId
WHERE SId=01;

#查看01同学的课程数
SELECT COUNT(*) AS 课程数
FROM sc
WHERE SId = 01;

#找出与01同学课程相同的其他同学的信息
SELECT *
FROM student 
WHERE student.`SId` IN 
(
SELECT SId
FROM sc
LEFT JOIN 
(
	SELECT CId,@r:=@r+1 AS rank
	FROM course,(SELECT @r:=0) AS r
) AS cr
ON sc.`CId` = cr.CId
GROUP BY sc.`SId`
HAVING SUM(rank) = 6
AND COUNT(*) = 3
AND SId <> 01
);


10. 查询没学过"张三"老师讲授的任一门课程的学生姓名 
#将张三老师的CId求出,再与sc表条件关联,可求出SId,再通过SId找学生信息。
SELECT s.Sname
FROM student AS s
WHERE s.SId NOT IN (
SELECT DISTINCT s.SId
FROM student AS s
JOIN sc
ON s.SId = sc.`SId`
WHERE sc.`CId` =(
SELECT c.CId
FROM teacher AS t
JOIN course AS c
ON t.TId = c.TId
WHERE t.Tname = '张三'));


11. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩 
#找出所有成绩不及格的学生,然后用GROUPBY进行分组,分组条件是不及格成绩数大于2的。
#这样能求学生的ID
SELECT s.SId,s.Sname,AVG(sc.`score`)
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
WHERE sc.`SId` IN  (
SELECT sc.`SId`
FROM sc
WHERE sc.`score` < 60
GROUP BY sc.`SId`
HAVING COUNT(sc.`SId`) >= 2)
GROUP BY sc.`SId`;

12. 检索" 01 "课程分数小于 60,按分数降序排列的学生信息
SELECT DISTINCT s.*
FROM student AS s
JOIN sc 
ON s.SId = sc.`SId`
WHERE s.SId IN (
SELECT sc.`SId`
FROM sc
WHERE sc.`CId` = '01'
AND sc.`score` < 60)
ORDER BY sc.`score`;

13. 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
SELECT sc.`SId`,sc.`score`,AVG(sc.`score`)
FROM sc
GROUP BY sc.SId
ORDER BY AVG(sc.`score`) DESC;

14. 查询各科成绩最高分、最低分和平均分:

    以如下形式显示:课程 ID,课程 NAME,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
    及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
    要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
# 这里用条件求和的方式来满足上面的划分

SELECT sc.`CId`,course.`Cname`,MAX(score) ,MIN(score),AVG(score),COUNT(sc.`SId`)
,SUM(IF(sc.`score`>=60,1,0))/COUNT(sc.`SId`) AS 及格率
,SUM(IF(sc.`score`>=70 AND  sc.`score`<80,1,0))/COUNT(sc.`SId`) AS 中等率
,SUM(IF(sc.`score`>=80 AND  sc.`score`<90,1,0))/COUNT(sc.`SId`) AS 优良率
,SUM(IF(sc.`score`>=90,1,0))/COUNT(sc.`SId`) AS 优秀率
FROM sc
LEFT JOIN course
ON sc.`CId` = course.`CId`
GROUP BY sc.`CId`
ORDER BY sc.`SId`,sc.`CId`;

15. 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
#对于这类题,求排名的,有个想法很重要:数据是逐条查询,每查询一次rank+1

#@rownum := @rownum + 1 中 := 是赋值的作用,这句话的意思是先执行@rownum + 1,然后把值赋给@rownum;
#(SELECT @rownum := 0) r 这句话的意思是设置rownum字段的初始值为0,即编号从1开始
# 举个例子,比如对成绩进行排名

#(SELECT @rownum := 0)派生表要加名
SELECT @rownum:=@rownum + 1,sc.`score`
FROM sc,(SELECT @rownum := 0) AS r
ORDER BY sc.`score` DESC;


SELECT CId,score,rank
FROM
(
SELECT *,
IF(@p=sc.`CId`,
	CASE
		WHEN @s=sc.`score` THEN @r
		WHEN @s:=sc.`score` THEN @r:=@r+1
	END,
	@r:=1) AS rank,
@p:=sc.`CId`,
@s:=sc.`score`
FROM sc ,(SELECT @p:='',@s:='',@r:=0) AS r
ORDER BY sc.`CId`,sc.`score` DESC
) AS s;

15.1 按各科成绩进行排序,并显示排名, Score 重复时合并名次

SELECT CId,score,rank
FROM(
	SELECT sc.*,IF(@p=sc.`CId`,@r:=@r+1,@r:=1) AS rank,@p:=sc.`CId`
	FROM sc,(SELECT @r:=0,@p='') AS r
	ORDER BY sc.`CId`,sc.`score` DESC
	) AS s;
	
	
16.  查询学生的总成绩,并进行排名,总分重复时保留名次空缺

SELECT (CASE WHEN @s=总成绩 THEN @r WHEN @s:=总成绩 THEN @r:=@r+1 END) AS rank,总成绩,SId
FROM 
(SELECT @r:=0,@s:='') AS r,
(SELECT SUM(sc.`score`) AS 总成绩,sc.`SId`
FROM sc
GROUP BY sc.`SId`
ORDER BY SUM(sc.`score`)  DESC) AS s;



16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺

SELECT 总成绩,SId,@rownum:=@rownum+1 AS rank
FROM 
(SELECT @rownum:=0) AS r,
(SELECT SUM(sc.`score`) AS 总成绩,sc.`SId`
FROM sc
GROUP BY sc.`SId`
ORDER BY SUM(sc.`score`)  DESC) AS s;


17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85][85-70][70-60][60-0] 及所占百分比
# 同14
SELECT sc.`SId`,c.Cname
,SUM(IF(sc.`score` >= 85 AND sc.`score` <100,1,0)) AS `[100-85]人数`
,SUM(IF(sc.`score` >= 85 AND sc.`score` <100,1,0))/COUNT(sc.`SId`) AS `[100-85]百分比`
,SUM(IF(sc.`score` >= 70 AND sc.`score` <85,1,0)) AS `[85-70]人数`
,SUM(IF(sc.`score` >= 70 AND sc.`score` <85,1,0))/COUNT(sc.`SId`) AS `[85-70]百分比`
,SUM(IF(sc.`score` >= 60 AND sc.`score` <70,1,0)) AS `[70-60]人数`
,SUM(IF(sc.`score` >= 60 AND sc.`score` <70,1,0))/COUNT(sc.`SId`) AS `[70-60]百分比`
,SUM(IF(sc.`score` >= 0 AND sc.`score` <60,1,0)) AS `[60-0]人数`
,SUM(IF(sc.`score` >= 0 AND sc.`score` <60,1,0))/COUNT(sc.`SId`) AS `[60-0]百分比`
FROM sc
LEFT JOIN course AS c
ON sc.`CId` = c.CId
GROUP BY sc.`CId`;


18. 查询各科成绩前三名的记录
#查询一科成绩前三名的记录,
#关于前三名记录的筛选,首先想到用limit,但这里limit和group by 不能一起用
#比自身成绩大的个数只有三个,创建两个sc表
# 方法一:
SELECT *
FROM sc AS s1
WHERE(
SELECT COUNT(*) FROM sc
WHERE sc.`CId`=s1.CId AND sc.`score` > s1.score)<3
ORDER BY CId,score DESC;

#方法二:
#对各组成绩排序后,取rank前三
SELECT CASE WHEN @s=sc.`score` THEN @r WHEN @:=sc.`score` THEN @r:@r+1 END,
FROM sc,(SELECT @r:=0,@s:='') AS r;

SELECT SId,CId,score,rank
FROM
(
SELECT *,
IF(@c=sc.`CId`,
CASE
	WHEN @s=sc.`score` 
	THEN @r
	WHEN @s:=sc.`score` 
	THEN @r:=@r+1
END,
@r:=1) AS rank,@c:=sc.`CId`,@s:=sc.`score`
FROM (SELECT @r:=0,@c:='',@s:='') AS r,sc
ORDER BY sc.`CId`,sc.`score` DESC
) AS s
WHERE rank < 4;

19. 查询每门课程被选修的学生数 
SELECT COUNT(*)
FROM sc
GROUP BY sc.`CId`;

20. 查询出只选修两门课程的学生学号和姓名 

SELECT s.SId,s.Sname
FROM student AS s 
LEFT JOIN sc
ON s.SId = sc.SId
GROUP BY s.SId
HAVING COUNT(sc.CId) = 2;


21. 查询男生、女生人数
SELECT SUM(IF(s.Ssex='男',1,0)) AS 男生人数
,SUM(IF(s.Ssex='女',1,0)) AS 女生人数
FROM student AS s;


22. 查询名字中含有「风」字的学生信息
SELECT s.*
FROM student AS s
WHERE s.Sname LIKE "%风%";


23. 查询同名同性学生名单,并统计同名人数
# 先找出同名同姓的学生名单,根据SId,求出
SELECT *
FROM student AS s
CROSS JOIN (
	SELECT s.Sname,s.Ssex,COUNT(*)
	FROM student AS s
	GROUP BY s.Sname
	HAVING COUNT(s.Sname) >= 2 AND COUNT(s.Ssex) >= 2
	) AS t
ON s.Sname = t.Sname;


24. 查询 1990 年出生的学生名单
SELECT *
FROM student
WHERE student.`Sage` LIKE('1990%');


25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT AVG(sc.`score`),sc.`CId`
FROM sc
GROUP BY sc.`CId`
ORDER BY AVG(sc.`score`) DESC,sc.`CId`;



26. 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩 
SELECT s.SId,s.Sname,AVG(sc.`score`)
FROM student AS s
JOIN sc
ON s.SId = sc.`SId`
GROUP BY s.SId
HAVING AVG(sc.`score`) >= 85;


27. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数 
SELECT s.Sname,sc.`score`
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
LEFT JOIN course AS c
ON sc.`CId` = c.CId
WHERE c.Cname = '数学'
AND sc.`score` < 60;


28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
SELECT s.*,sc.`CId`,sc.`score`
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
LEFT JOIN course AS c
ON sc.`CId` = c.CId;


29. 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
SELECT s.Sname,c.Cname,sc.`score`
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
LEFT JOIN course AS c
ON sc.`CId` = c.CId
WHERE sc.score > 70; 


30. 查询不及格的课程
SELECT DISTINCT c.Cname
FROM sc
LEFT JOIN course AS c
ON sc.`CId` = c.CId
WHERE sc.score < 60;

31. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
SELECT s.Sname,s.SId,sc.`score`
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
LEFT JOIN course AS c
ON sc.`CId` = c.CId
WHERE c.CId = '01'
AND sc.`score` >= 80;



32. 求每门课程的学生人数 
SELECT c.CId,COUNT(*)
FROM sc
LEFT JOIN course AS c
ON sc.`CId` = c.CId
GROUP BY c.CId;


33. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
#可以用sql99语法的join来进行关联,但是4个表关联需要写的东西有些多。这样写能简洁一些。
SELECT student.*,sc.`score`
FROM student,sc,course,teacher
WHERE teacher.Tname = '张三'
AND student.`SId`=sc.`SId`
AND sc.`CId` = course.`CId`
AND course.`TId` = teacher.`TId`
ORDER BY sc.`score` DESC
LIMIT 1;


34. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT SId,Sname,Sage,Ssex,score,rank
FROM
(
SELECT *,(CASE WHEN @s= score THEN @r WHEN @s:=score THEN @r:=@r+1 END) AS rank,@s:=score
FROM (SELECT @r:=0,@s:='') AS r,
(SELECT s.*,score
FROM student AS s,sc,teacher AS t,course AS c
WHERE s.`SId` = sc.`SId`
AND c.CId = sc.`CId`
AND c.TId = t.TId
AND t.Tname = '张三'
ORDER BY score DESC
) AS w
) AS e
WHERE rank = 1;

35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩 
SELECT *
FROM sc
GROUP BY sc.`score`
HAVING COUNT(*) >= 2;

36. 查询每门功成绩最好的前两名
#方法一:
#这里对比下这两种写法
SELECT  *
FROM sc AS s1
WHERE(
	SELECT COUNT(*)
	FROM sc 
	WHERE sc.`CId`=s1.CId AND sc.`score` > s1.score
) <2
ORDER BY CId,score DESC;


SELECT *
FROM sc AS s1
WHERE(
	SELECT COUNT(*) 
	FROM sc
	WHERE sc.`CId`=s1.CId AND sc.`score` < s1.score
)<2
ORDER BY CId,score DESC;

#方法二:
SELECT SId,CId,score,rank
FROM(
SELECT *,
IF(@c=CId,
	CASE 
		WHEN @s=score THEN @r
		WHEN @s:=score THEN @r:=@r+1
	END,
@r:=1) AS rank,
@c:=CId,
@s:=score
FROM 
(SELECT @r:=0,@c:='',@s:='') AS r,
(SELECT *
FROM sc
ORDER BY sc.`CId`,sc.`score` DESC) AS s
) AS q
WHERE rank <3;


37. 统计每门课程的学生选修人数(超过 5 人的课程才统计)。
SELECT sc.`CId`,COUNT(sc.SId)
FROM sc
GROUP BY sc.`CId`
HAVING COUNT(sc.SId) > 5;

38. 检索至少选修两门课程的学生学号 
SELECT sc.`SId`
FROM sc
GROUP BY sc.`SId`
HAVING COUNT(*) >= 2;

39. 查询选修了全部课程的学生信息
SELECT *
FROM student AS s
LEFT JOIN sc
ON s.SId = sc.`SId`
GROUP BY sc.SId
HAVING COUNT(*)=(
	SELECT DISTINCT COUNT(*)
	FROM course
) ;

40. 查询各学生的年龄,只按年份来算 
# TIMESTAMPDIFF求两个时间差,前面的是格式
SELECT student.`SId`,student.`Sname`,TIMESTAMPDIFF(YEAR,student.Sage,CURDATE()) AS 年龄
FROM student;

41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
SELECT student.`SId`,student.`Sname`,TIMESTAMPDIFF(YEAR,student.Sage,CURDATE()) AS 年龄
FROM student;

42. 查询本周过生日的学生
#这里用到时间函数WEEKOFYEAR(),返回当前时间curdate())是第几周
#解法就是找出学生的出生日期在第几周,然后跟当前的周数对比,看是否对应
SELECT *
FROM student AS s
WHERE WEEKOFYEAR(s.`Sage`) = WEEKOFYEAR(CURDATE());

43. 查询下周过生日的学生
#同上。查询下周过生日,即学生的生日周数比当前时间大1
SELECT *
FROM student AS s
WHERE WEEKOFYEAR(s.`Sage`) = WEEKOFYEAR(CURDATE())+1;

44. 查询本月过生日的学生
#用到时间函数month(),获得当前月数
#解法同上面的周数
SELECT *
FROM student AS s
WHERE MONTH(s.`Sage`) = MONTH(CURDATE());

45. 查询下月过生日的学生
SELECT *
FROM student AS s
WHERE MONTH(s.`Sage`) = MONTH(CURDATE())+1;

数据来源

超经典SQL练习题,做完这些你的SQL就过关了

发布了26 篇原创文章 · 获赞 29 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/AvenueCyy/article/details/105198542