题记:从知乎上看到的一篇文章,恰好最近工做中发现遇到的题目与这个几乎同样,可能就是从这里来的吧。^_^sql
里面的答案没有细看,SQL求解重在思路,不少时候同一种结果可能有多种写法,好比题中的各科成绩取前三名,我是在看到这篇文章想到的另外一种写法,不过题中的写法也能够作为参考学习。以此记录。函数
如下转自:https://zhuanlan.zhihu.com/p/72223558学习
这篇文写了挺久了,有一位细心的小伙伴滑稽发现了一个错误,很感谢有人认真的在看,我从新修改了一下! 测试
好久以前我写过一篇学习sql的基本操做,可是本身好像在sql上面有点停滞了。最近有和一位朋友聊过如何学习sql,朋友给个人回复是多写代码。我深觉得然因而就找到了这个经典的50题。spa
虽然这个经典50题网上有不少人分享过,可是,只有本身实际操做过之后才能真正的理解其中的坑,也才可以加深对知识的理解吧。我但愿本身可以作一套很详细的解析。.net
解析包含:1解题思路,2相关知识,3 实际语句实现;3d
申明:我只是一个初学者,还有不少不懂的地方,因此若是您发现了错误,但愿能在下边提出来,万分感谢!code
若是你以为我很走心,也欢迎点赞!orm
首先建表,主要有四个表,学生表(Student),课程表(Course),教师表(Teacher),以及成绩表(SC)blog
在分别介绍一下每一个表的字段 学生表(Student )有四个字段 sid--学生id,sname--学生姓名,sage--学生年龄,ssex--学生性别
课程表(Course)有三个字段,cid--课程id,cname--课程名,tid--教师id
教师表(Teacher)有两个字段,tid--教师id,tname--教师姓名
成绩表(SC)有三个字段,sid--学生id,cid--课程id,score--成绩
咱们用脑图的方式绘制出来,以下所示
学生表结构
课程表结构
教师表结构
成绩表结构
各个表之间的关系以下,Student和SC表经过学生id(sid)来链接,Course和Teacher表经过教师id(tid)链接,SC和Course表经过课程id(cid)来链接。
create table Student(sid varchar(10),sname varchar(10),sage datetime,ssex nvarchar(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('08' , '王菊' , '1990-01-20' , '女'); create table Course(cid varchar(10),cname varchar(10),tid varchar(10)); insert into Course values('01' , '语文' , '02'); insert into Course values('02' , '数学' , '01'); insert into Course values('03' , '英语' , '03'); create table Teacher(tid varchar(10),tname varchar(10)); insert into Teacher values('01' , '张三'); insert into Teacher values('02' , '李四'); insert into Teacher values('03' , '王五'); 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"课程成绩高的学生的信息及课程分数
解题思路:要查询的是两个课程的成绩,并且还要显示学生的信息。因此须要用到两张表,SC,Student这两张表。
问题拆分:(1) 怎么查找两个课程的成绩呢? (2) 如何把课程表和学员信息表链接起来呢?
那么用到哪些知识呢?
(1) 子查询 (2) join
语句实现:先找到两门课的成绩
-- 课程1的成绩 SELECT sid ,score AS class1 FROM sc WHERE sc.cid = '01'; -- 课程2的成绩 SELECT sid,score AS class2 FROM sc WHERE sc.cid = '02';
class1 查询结果
class2 查询结果
两个子查询结束了之后,下一步就是使用join把这两个查询的结果链接起来
SELECT * FROM Student RIGHT JOIN (SELECT t1.sid,class1,class2 FROM -- 这个是要查询两个表的成绩,即课程1大于课程2 (SELECT sid ,score AS class1 FROM sc WHERE sc.cid = '01') AS t1, (SELECT sid,score AS class2 FROM sc WHERE sc.cid = '02') AS t2 WHERE t1.sid = t2.sid AND t1.class1 > t2.class2) r -- 这里是固定的,就是子查询的一个别名的设置 -- 这一步就是把两个表按照sid联结起来 ON Student.sid = r.sid;
最终查询结果
好的,,第一题就解决了
第二题:1.1 查询存在" 01 "课程但可能不存在" 02 "课程的状况(不存在时显示为 null )
思路:首先要查询全部的学生的选课状况,而后找到选择课程1和选择课程2的学生
解决方法: 使用join
选择两个分别选择课程1和课程2的学员表,而后把这两个表join起来
SELECT * FROM(SELECT * FROM sc WHERE sc.cid = '01' ) t1 LEFT JOIN (SELECT * FROM sc WHERE sc.cid = '02') t2 ON t1.sid = t2.sid ;
输出结果
1.2 查询同时存在01和02课程的状况
思路:要求同时选择了01和02课程的状况,则须要使用where连接起来,这一题和上一题相比就是多了一个去除选了01可是没有选择02课程的这一部分
知识点:子查询,where语句
SELECT * FROM (SELECT * FROM sc WHERE sc.cid = '01') AS t1, (SELECT * FROM sc WHERE sc.cid = '02') AS t2 WHERE t1.sid = t2.sid;
执行结果
1.3 查询选择了02课程但没有01课程的状况
思路,要求首先获得选择了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 * FROM sc WHERE sc.sid NOT IN (SELECT sid FROM sc WHERE sc.cid = '01') AND sc.cid = '02';
执行结果
小结:上面几个题基本能够说是同一类型,要注意子查询的使用,以及join和where的区别
2.查询平均成绩大于等于 60 分的同窗的学生编号和学生姓名和平均成绩
思路:看到这个题的时候第一想法是要使用group by,和having,又由于成绩表(sc)没有学生姓名,因此还要使用join,固然avg确定是须要的
考察知识:group by,join
SELECT s.sid,sname,AVG(sc.score) FROM student AS s INNER JOIN sc ON s.sid = sc.sid GROUP BY sc.sid HAVING AVG(sc.score) >= 60;
执行结果
还有一种解法,使用子查询
SELECT r.*, s.sname FROM (SELECT sid,AVG(score) FROM sc GROUP BY sid HAVING AVG(score) > 60) r LEFT JOIN student AS s ON s.sid = r.sid;
3.查询在 SC 表存在成绩的学生信息
思路:这题比较简单,就是两张表经过id链接,而后求单独值
知识点:Distinct
SELECT DISTINCT student.* FROM sc,student WHERE student.sid = sc.sid ;
执行结果
4.查询全部同窗的学生编号、学生姓名、选课总数、全部课程的成绩总和
解题思路:首先用到两张表格,而后要求选课总数,和成绩总和,那么就须要用到groupby 和sum以及count
知识点:gruop by, sum,join,count
SELECT s.sid,s.sname,COUNT(sc.cid),SUM(score) FROM student AS s INNER JOIN sc ON s.sid = sc.sid GROUP BY sc.sid;
执行结果
5.查询「李」姓老师的数量
解题思路:这题考的是通配符的查询,好比使用like和%
知识点:count,like,%
SELECT COUNT(*) FROM teacher WHERE tname LIKE ('李%');
执行结果
6.查询学过「张三」老师授课的同窗的信息
解题思路:要查找张三老师的授课科目,而后经过科目和score表链接,而后再和学生表链接
知识点:就是多重链接 inner join
SELECT s.* FROM student AS s INNER JOIN sc ON s.sid = sc.sid INNER JOIN course AS c ON sc.cid = c.cid INNER JOIN teacher AS t ON t.tid = c.tid WHERE t.tname = '张三';
执行结果
7.查询没有学全全部课程的同窗的信息
解题思路:首先利用子查询查询course表查询获得共有几门课,按照groupby的方式求课程数加上having小于查询出来的课程的全部学员信息就好
知识点:子查询,groupby,having,join
SELECT s.*,COUNT(cid) FROM sc RIGHT JOIN student AS s ON sc.sid = s.sid GROUP BY sc.sid HAVING COUNT(cid) < (SELECT COUNT(DISTINCT cid) FROM course);
执行结果
网友的有一种比较好的作法,是使用not in
SELECT s.* FROM student AS s WHERE s.sid NOT IN (SELECT sc.sid FROM sc GROUP BY sc.sid HAVING COUNT(cid) >= 3);-- 这一句也可使用子查询
执行结果
8.查询至少有一门课与学号为" 01 "的同窗所学相同的同窗的信息
解题思路:首先要查询出01同窗所学的课程,而后使用cid in 01同窗的课程,并排除sid=01的同窗
SELECT s.* FROM sc INNER JOIN student AS 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;
执行结果
我这里使用了groupby语句来求取单个学员id,也可使用distinct关键字来作区分
SELECT DISTINCT s.* FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE sc.cid IN (SELECT cid FROM sc WHERE sid = '01') AND sc.sid != '01';
执行结果
这里就有一个知识点就是group by有去除重复值的功能,这个其实不难理解,由于group by就是按照单个组分类,能够理解为按照同一类进行切分
9.查询和" 01 "号的同窗学习的课程彻底相同的其余同窗的信息
解题思路:首先感受真题很难,想法是在student表的sid在sc的id中,而这个id又和cid相关联,而后再查询结束时,还要排除id=01的状况。反正很复杂。。。
知识点:n重子查询,in的使用
SELECT * FROM student WHERE sid IN (SELECT sid FROM (SELECT * FROM sc AS a WHERE cid IN (SELECT cid FROM sc WHERE sid = 01)) b GROUP BY sid HAVING COUNT(cid) = (SELECT COUNT(cid) FROM sc c WHERE sid = 01)) AND sid != 01 ; SELECT * FROM student WHERE sid IN (SELECT sid FROM (SELECT * FROM sc AS a WHERE cid IN (SELECT cid FROM sc WHERE sid = 01)) b GROUP BY sid HAVING COUNT(cid) = (SELECT COUNT(cid) FROM sc c WHERE sid = 01)) AND sid != 01 ;
10.查询没学过"张三"老师讲授的任一门课程的学生姓名
解题思路:1先要查询出张三老师的教授课程,2而后利用not in 来找到学生的id
知识点:子查询,not in,多重join
SELECT sname FROM student WHERE sid NOT IN ( SELECT sid FROM sc LEFT JOIN course ON sc.cid=course.cid LEFT JOIN teacher ON course.tid=teacher.tid WHERE tname='张三' )
11.查询两门及其以上不及格课程的同窗的学号,姓名及其平均成绩
解题思路:题中提到了两门及以上的不及格课程,所以考虑使用Groupby 和 having,题中还提到学生姓名以及平均成绩,考虑到这里还要求出平均成绩,可是平均成绩说明不是很清楚,
知识点:Group by ,having,以及子查询在from子句中的使用
SELECT sname,s.sid,AVG(sc1.score) AS avg_score FROM (SELECT * FROM sc WHERE score < 60)sc1, student AS s WHERE sc1.sid=s.sid GROUP BY sc1.sid HAVING COUNT(sc1.cid)>=2;
12.检索" 01 "课程分数小于 60,按分数降序排列的学生信息
解题思路:要求01课程小于60的学员信息,而后按照降序排列学员信息
知识点:就是很简单的order by
SELECT s.* FROM sc,student AS s WHERE cid = '01' AND score <60 AND sc.sid = s.sid ORDER BY score DESC;
固然还有其余解法,好比使用join,这里就很少写了
13.按平均成绩从高到低显示全部学生的全部课程的成绩以及平均成绩
解题思路:要按照平均成绩降序排列,则须要使用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 ORDER BY avg_score DESC) r ON s.sid = r.sid ;
能够发现这里的作法,发现并无按照我想要的平均成绩的从高到低来排序,因此就去排查一下缘由,发现这个错误是执行顺序的关系。
正确作法
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 ;
这样就能够了,所以啊,sql执行顺序仍是要牢记的
14.查询各科成绩最高分、最低分和平均分,以以下形式显示:
以以下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,
优良率,优秀率
及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序
排列
解题思路:这里要把最高分,最低分,平均分,等多个维度,那么就须要使用case when 语句了还有就是函数的使用
知识点:case when 别名的使用,以及函数的使用,和函数的嵌套使用,题目后边还考到了多列排列的使用,先按照desc,后按照asc排列
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 ;
特别长,可是知识很简单,就是case when语句的使用
15.按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
解题思路:两张成绩表链接,而后按照成绩大小作一个排名
知识点:排序相关知识
SELECT a.*, COUNT(a.score) AS 排名 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 ORDER BY a.cid, 排名 ;
15.1 按各科成绩进行行排序,并显示排名, Score 重复时合并名次
解题思路:相比于上一题这里多了一个合并名次的事情,所谓名次合并,意思是两我的的成绩一致按照一个名次来,好比两个成绩同样的排名第一,下一个排名第二的就当作第三名
SELECT a.*, COUNT(b.score)+1 AS 排名 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 ORDER BY a.cid, 排名 ;
16.查询学生的总成绩,并进行排名,总分重复时保留名次空缺
解题思路:和15题差很少,不过我要引入一个用户变量
知识点:用户变量的使用
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 ;
17. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
解题思路:这个题和以前的那一题很像,都是使用case when 语句,而后加一个join
知识点:join case when,以及
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 ;
18.查询各科成绩前三名的记录
解题思路:按照课程id和学生id来分组,而后合并两个sc表,找到第一个表的成绩比第二个表成绩低的的值,而后排序
知识点: join groupby以及having的使用,固然还有order by的使用
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;
19.查询每门课程被选修的学生数
解题思路:就是很简单的按照cid分组,而后计算每一个组里面的学生人数,因为前面几题都是想了好久,遇到这题,我居然不敢相信这么简单
知识点:groupby
SELECT cid,COUNT(sid) AS num FROM sc GROUP BY cid;
20.查询出只选修两门课程的学生学号和姓名
解题思路:查询选择了两门课的学生,而后链接student表,还算是比较基础的题
知识点:groupby having join
SELECT sc.sid,sname FROM sc INNER JOIN student ON sc.sid = student.sid GROUP BY sc.sid HAVING COUNT(sc.cid) = 2;
21. 查询男生、女生人数
解题思路:男女生人数这个毫无疑问考的是groupby 还有就是分组之后的count,或者可使用case when
知识点:groupby,或者 case when
SELECT ssex,COUNT(ssex) as FROM student GROUP BY ssex;
SELECT SUM(CASE WHEN ssex='男' THEN 1 ELSE 0 END)AS 男生人数, SUM(CASE WHEN ssex='女' THEN 1 ELSE 0 END) AS 女生人数 FROM student;
固然这里不完美的,可使用count(sid)-男生人数,有不少的方式。
22. 查询名字中含有「风」字的学生信息
解题思路:很简单的一题,就是考察通配符,而考察点是是否有风
知识点:通配符%
SELECT * FROM student WHERE sname LIKE '%风%';
23查询同名同性学生名单,并统计同名人数
解题思路:同名同性,咱们须要的是count(sname)>1,还要作一步筛选。这里有一个小坑,开始的时候我觉得是同名同姓,中国文化博大精深啊
知识点:having,groupby
SELECT sname,COUNT(sname) AS 同名人数 FROM student GROUP BY sname HAVING 同名人数>1;
因为这个数据表中没有同名的人数,因此显示结果如上。
24.查询 1990 年出生的学生名单
解题思路:很简单的题,可是我仍是作错了
知识点:通配符
SELECT sname FROM student WHERE sage LIKE '1990%';
本觉得能够很快的执行并产生结果,可是没想到报错了,看一下报错信息,睡是datetime error,这个是什么缘由呢,咱们看一下,以前创表的语句
原来本来的建表的时候就是设置了datetime类型,那这里就要使用date函数了,这里对date函数作一些介绍
网上搜的图
我以为上面的图可以很好的说明经常使用的时间函数处理,无非就是hour(小时),minute(分钟),second(秒),day(天),week(周),month(月),quarter(季度),year(年度)
那么这一题,显然就是要使用year了
SELECT * FROM student WHERE YEAR(sage) LIKE '1990%';
好的,很完美的解决了问题
25.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编
号升序排列
解题思路:按照课程分组,而后求分组之后的平均值。而后外加一个排序,排序顺序按照课程id升序排列
知识点:group by ,order by
SELECT cid,AVG(score) FROM sc GROUP BY cid ORDER BY AVG(score) DESC,cid;
因为这个表里面只有3门课,因此这里显示不出来,若是有不少数据,而后又刚好有相同的id
的时候应该就能够看出不一样了
26.查询平均成绩大于等于 85 的全部学生的学号、姓名和平均成绩
解题思路:按照学生id分组,而后求平均分,而后用having语句判断平均分大于等于85,又由于要查询学生姓名所以可使用join,或者直接使用笛卡尔积,可是笛卡尔积对于数据量比较大的时候不宜使用
知识点:having,groupby,join
SELECT sc.sid,sname,AVG(score) AS 平均成绩 FROM sc,student WHERE sc.sid = student.sid GROUP BY sc.sid HAVING 平均成绩>= 85;
或者
SELECT sc.sid,sname,AVG(score) AS 平均成绩 FROM sc INNER JOIN student ON sc.sid = student.sid GROUP BY sc.sid HAVING 平均成绩>= 85;
结果都是第同样的,可是数据里大的时候我会使用第二种解法
27.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
解题思路:和上一题同样,可使用join,也能够直接使用笛卡尔积,可是要使用三张表,因此最好仍是使用join
知识点:多重join的使用
SELECT sname, score FROM course AS c INNER JOIN sc ON c.cid = sc.cid AND c.cname = '数学' AND sc.score < 60 INNER JOIN student AS s ON sc.sid = s.sid ;
28. 查询全部学生的课程及分数状况(存在学生没成绩,没选课的状况)
解题思路:要把学生的姓名展现出来,因此使用join
知识点:join的使用
SELECT sname, sc.cid, score FROM sc INNER JOIN student AS s ON sc.sid = s.sid ;
29.查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
解题思路:就是在上一题的基础上,加上一个where条件判断,或者直接在join on后边判断
知识点:join加上条件判断
SELECT sname, sc.cid, score FROM sc INNER JOIN student AS s ON sc.sid = s.sid AND score > 70 ;
或者
SELECT sname, sc.cid, score FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE score > 70 ;
结果是同样的,至于二者的区别,能够参考下面这篇文章https://blog.csdn.net/weixin_40539892/article/details/90263677
总结起来就是inner join后边时两个作法是没有区别的,可是若是是left join这种就会有多余的出来了,这是由于使用join之后会生成一个虚拟表,而使用where是在这张虚拟表的基础上进行筛选,因此结果可能不同。这个值得注意。
30.查询不及格的课程
解题思路:这个其实和上面一题是同一个考法,不详细展开,惟一的区别就是只查询课程,因此就是要distinct,或者groupby
知识点:join,
SELECT sc.cid FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE score < 60 GROUP BY sc.cid
第二种使用distinct
SELECT DISTINCT sc.cid FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE score < 60 ;
31.查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
解题思路:首先确定须要join把两个表连起来,而后使用条件查询课程id为01且成绩大于80
知识点:join where
SELECT sc.sid,sname FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE sc.cid = 01 AND score >= 80;
32.求每门课程的学生人数
解题思路:就是简单的按照课程分组而后求sid的人数
知识点:group by ,count
SELECT cid,COUNT(sid) AS 人数 FROM sc GROUP BY cid;
33.成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
解题思路:这题首先要找到张三老师所授课程,而后找到选择这门课程的学生,在成绩按照从大到小的顺序排列,而后只取最高的成绩,固然还须要使用子查询
知识点:join,limit
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.cid AND tname = '张三') ORDER BY score DESC LIMIT 1 ;
如今慢慢有点感受了,可以很快写出来,果真这种语言相关的仍是要多敲代码,不要怕错,就是乌龟的速度,只要一直往前也有机会超过兔子
34.成绩有重复的状况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生
信息及其成绩
解题思路:有重复成绩,咱们就选择一个最大成绩而后使用子查询,让成绩在各科成绩的最大值里面作筛选
知识点:多重join,以及子查询的应用
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 = '张三') ;
因为我建立的表格里面没有重复的成绩,因此返回结果没有发生变化
35.查询不一样课程成绩相同的学生的学生编号、课程编号、学生成绩
解题思路:首先join两张表,而后作筛选1成绩相同,2课程id不相同
知识点:join,以及where的使用
SELECT DISTINCT a.* FROM sc AS a INNER JOIN sc AS b WHERE a.score = b.score AND a.cid != b.cid ;
因为可能使用的是inner join,因此可能会有不少重复值,所以我用了一个distinct的作法。
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 ;
我以为这个题仍是相对来讲好理解的,一样的查询前3名等等,只需改一个数字。
37. 统计每门课程的学生选修人数(超过 5 人的课程才统计)。
解题思路:按照课程分组,而后count人数,使用having作一个筛选
知识点:groupby having
SELECT cid, COUNT(sid) FROM sc GROUP BY cid HAVING COUNT(sid) > 5 ;
38.检索至少选修两门课程的学生学号
解题思路:和上一题基本相似按照学生id分组而后count cid,筛选出大于等于2的学生
知识点:groupby having
SELECT sid, COUNT(cid) FROM sc GROUP BY sid HAVING COUNT(cid) >= 2 ;
39.查询选修了所有课程的学生信息
解题思路:一样的咱们要知道总共有多少门课,不光是为了回答这一道题,可能真实状况会有不少的课,那么就须要把course表中全部的课程计数,还要求学生信息,那就须要使用join了
知识点:join,where,子查询
SELECT s.* FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE cid = (SELECT COUNT(*) FROM course) ;
40.查询各学生的年龄,只按年份来算
解题思路:这题开始就要使用时间函数了,不难,还算比较简单
知识点:date函数的使用
SELECT sname, YEAR(NOW()) - YEAR(sage) AS 年纪 FROM student ;
41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
解题思路:这个可使用case when语句,而后使用时间戳求差值
知识点:case when ,year,date_format
SELECT sname, CASE WHEN ( DATE_FORMAT(NOW(), '%m-%d') - DATE_FORMAT(sage, '%m-%d') ) < 0 THEN YEAR(NOW()) - YEAR(sage) + 1 ELSE YEAR(NOW()) - YEAR(sage) END AS 年龄 FROM student ;
42.查询本周过生日的学生
解题思路:使用week函数
知识点:week,now
SELECT sname FROM student WHERE WEEK(sage) = WEEK(NOW());
能够发现没有结果,为了验证准确性,咱们把student表格单独拉出来
SELECT * FROM student ;
能够看到果真没有,那么为了进一步验证,咱们向student表中新增一行数据
INSERT INTO Student VALUES('09' , '关羽' , '1990-07-15' , '男'); SELECT * FROM student ;
看一下执行结果
在执行如下咱们以前的语句
ok看来语句是没有毛病的,我也不知道为啥非要验证如下,多是强迫症吧。。。
43. 查询下周过生日的学生
解题思路:好的嘛,下周过生日,表明着在上题的基础上再加1
知识点:week,now
SELECT sname FROM student WHERE WEEK(sage) = WEEK(NOW()) + 1 ;
固然仍是没有结果的,不过这里就不作测试了
44.查询本月过生日的学生
解题思路:基本相似的操做,使用month函数
知识点:month,now
SELECT sname, sage FROM student WHERE MONTH(sage) = MONTH(NOW());
45.查询下月过生日的学生
解题思路:一样的套路,一样的解法
知识点:month,now
SELECT sname, sage FROM student WHERE MONTH(sage) = MONTH(NOW()) + 1 ;
哇哦,不知不觉间就到了最后一题了,这里给我印象最深的是那几个须要排序的题,我以为排序的题,要好好琢磨,争取可以很快的写出来。
人果真都是有惰性的,这一篇没想到拖了这么久,不过可以在工做休息之余写完这篇文仍是很开心的,接下来,要继续刷题,下一篇应该就是牛客网和leetcode上面的题了。加油!
话说写了这么长的文,不给个赞吗?