这个是网上流传的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)
练习题目
- 查询" 01 “课程比” 02 "课程成绩高的学生的信息及课程分数
1.1 查询同时存在" 01 “课程和” 02 "课程的情况
1.2 查询存在" 01 “课程但可能不存在” 02 "课程的情况(不存在时显示为 null )
1.3 查询不存在" 01 “课程但存在” 02 "课程的情况
-
查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
-
查询在 SC 表存在成绩的学生信息
-
查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
4.1 查有成绩的学生信息
-
查询「李」姓老师的数量
-
查询学过「张三」老师授课的同学的信息
-
查询没有学全所有课程的同学的信息
-
查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
-
查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息
-
查询没学过"张三"老师讲授的任一门课程的学生姓名
-
查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
-
检索" 01 "课程分数小于 60,按分数降序排列的学生信息
-
按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
-
查询各科成绩最高分、最低分和平均分:
以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
- 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
15.1 按各科成绩进行排序,并显示排名, Score 重复时合并名次
- 查询学生的总成绩,并进行排名,总分重复时保留名次空缺
16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
-
统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
-
查询各科成绩前三名的记录
-
查询每门课程被选修的学生数
-
查询出只选修两门课程的学生学号和姓名
-
查询男生、女生人数
-
查询名字中含有「风」字的学生信息
-
查询同名同性学生名单,并统计同名人数
-
查询 1990 年出生的学生名单
-
查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
-
查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
-
查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
-
查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
-
查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
-
查询不及格的课程
-
查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
-
求每门课程的学生人数
-
成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
-
成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
-
查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
-
查询每门功成绩最好的前两名
-
统计每门课程的学生选修人数(超过 5 人的课程才统计)。
-
检索至少选修两门课程的学生学号
-
查询选修了全部课程的学生信息
-
查询各学生的年龄,只按年份来算
-
按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
-
查询本周过生日的学生
-
查询下周过生日的学生
-
查询本月过生日的学生
-
查询下月过生日的学生
参考答案
由于本人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;
数据来源
转载:https://blog.csdn.net/AvenueCyy/article/details/105198542