一些关于SQL的简单练习题

注:以下所有言论仅个人意见和想法,更多是为了本人定期练习和朋友参考,有错误欢迎指出,不喜勿喷,谢谢大家。

1.建库(首先搭建数据库练习题的表结构和数据信息)
一些关于SQL的简单练习题_第1张图片
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;


– Table structure for class


DROP TABLE IF EXISTS class;
CREATE TABLE class (
cid int(11) NOT NULL AUTO_INCREMENT,
caption varchar(32) NOT NULL,
PRIMARY KEY (cid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


– Records of class


BEGIN;
INSERT INTO class VALUES (‘1’, ‘三年二班’), (‘2’, ‘三年三班’), (‘3’, ‘一年二班’), (‘4’, ‘二年九班’);
COMMIT;


– Table structure for course


DROP TABLE IF EXISTS course;
CREATE TABLE course (
cid int(11) NOT NULL AUTO_INCREMENT,
cname varchar(32) NOT NULL,
teacher_id int(11) NOT NULL,
PRIMARY KEY (cid),
KEY fk_course_teacher (teacher_id),
CONSTRAINT fk_course_teacher FOREIGN KEY (teacher_id) REFERENCES teacher (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


– Records of course


BEGIN;
INSERT INTO course VALUES (‘1’, ‘生物’, ‘1’), (‘2’, ‘物理’, ‘2’), (‘3’, ‘体育’, ‘3’), (‘4’, ‘美术’, ‘2’);
COMMIT;


– Table structure for score


DROP TABLE IF EXISTS score;
CREATE TABLE score (
sid int(11) NOT NULL AUTO_INCREMENT,
student_id int(11) NOT NULL,
course_id int(11) NOT NULL,
num int(11) NOT NULL,
PRIMARY KEY (sid),
KEY fk_score_student (student_id),
KEY fk_score_course (course_id),
CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES course (cid),
CONSTRAINT fk_score_student FOREIGN KEY (student_id) REFERENCES student (sid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


– Records of score


BEGIN;
INSERT INTO score VALUES (‘1’, ‘1’, ‘1’, ‘10’), (‘2’, ‘1’, ‘2’, ‘9’), (‘5’, ‘1’, ‘4’, ‘66’), (‘6’, ‘2’, ‘1’, ‘8’), (‘8’, ‘2’, ‘3’, ‘68’), (‘9’, ‘2’, ‘4’, ‘99’), (‘10’, ‘3’, ‘1’, ‘77’), (‘11’, ‘3’, ‘2’, ‘66’), (‘12’, ‘3’, ‘3’, ‘87’), (‘13’, ‘3’, ‘4’, ‘99’), (‘14’, ‘4’, ‘1’, ‘79’), (‘15’, ‘4’, ‘2’, ‘11’), (‘16’, ‘4’, ‘3’, ‘67’), (‘17’, ‘4’, ‘4’, ‘100’), (‘18’, ‘5’, ‘1’, ‘79’), (‘19’, ‘5’, ‘2’, ‘11’), (‘20’, ‘5’, ‘3’, ‘67’), (‘21’, ‘5’, ‘4’, ‘100’), (‘22’, ‘6’, ‘1’, ‘9’), (‘23’, ‘6’, ‘2’, ‘100’), (‘24’, ‘6’, ‘3’, ‘67’), (‘25’, ‘6’, ‘4’, ‘100’), (‘26’, ‘7’, ‘1’, ‘9’), (‘27’, ‘7’, ‘2’, ‘100’), (‘28’, ‘7’, ‘3’, ‘67’), (‘29’, ‘7’, ‘4’, ‘88’), (‘30’, ‘8’, ‘1’, ‘9’), (‘31’, ‘8’, ‘2’, ‘100’), (‘32’, ‘8’, ‘3’, ‘67’), (‘33’, ‘8’, ‘4’, ‘88’), (‘34’, ‘9’, ‘1’, ‘91’), (‘35’, ‘9’, ‘2’, ‘88’), (‘36’, ‘9’, ‘3’, ‘67’), (‘37’, ‘9’, ‘4’, ‘22’), (‘38’, ‘10’, ‘1’, ‘90’), (‘39’, ‘10’, ‘2’, ‘77’), (‘40’, ‘10’, ‘3’, ‘43’), (‘41’, ‘10’, ‘4’, ‘87’), (‘42’, ‘11’, ‘1’, ‘90’), (‘43’, ‘11’, ‘2’, ‘77’), (‘44’, ‘11’, ‘3’, ‘43’), (‘45’, ‘11’, ‘4’, ‘87’), (‘46’, ‘12’, ‘1’, ‘90’), (‘47’, ‘12’, ‘2’, ‘77’), (‘48’, ‘12’, ‘3’, ‘43’), (‘49’, ‘12’, ‘4’, ‘87’), (‘52’, ‘13’, ‘3’, ‘87’);
COMMIT;


– Table structure for student


DROP TABLE IF EXISTS student;
CREATE TABLE student (
sid int(11) NOT NULL AUTO_INCREMENT,
gender char(1) NOT NULL,
class_id int(11) NOT NULL,
sname varchar(32) NOT NULL,
PRIMARY KEY (sid),
KEY fk_class (class_id),
CONSTRAINT fk_class FOREIGN KEY (class_id) REFERENCES class (cid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


– Records of student


BEGIN;
INSERT INTO student VALUES (‘1’, ‘男’, ‘1’, ‘理解’), (‘2’, ‘女’, ‘1’, ‘钢蛋’), (‘3’, ‘男’, ‘1’, ‘张三’), (‘4’, ‘男’, ‘1’, ‘张一’), (‘5’, ‘女’, ‘1’, ‘张二’), (‘6’, ‘男’, ‘1’, ‘张四’), (‘7’, ‘女’, ‘2’, ‘铁锤’), (‘8’, ‘男’, ‘2’, ‘李三’), (‘9’, ‘男’, ‘2’, ‘李一’), (‘10’, ‘女’, ‘2’, ‘李二’), (‘11’, ‘男’, ‘2’, ‘李四’), (‘12’, ‘女’, ‘3’, ‘如花’), (‘13’, ‘男’, ‘3’, ‘刘三’), (‘14’, ‘男’, ‘3’, ‘刘一’), (‘15’, ‘女’, ‘3’, ‘刘二’), (‘16’, ‘男’, ‘3’, ‘刘四’);
COMMIT;


– Table structure for teacher


DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher (
tid int(11) NOT NULL AUTO_INCREMENT,
tname varchar(32) NOT NULL,
PRIMARY KEY (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


– Records of teacher


BEGIN;
INSERT INTO teacher VALUES (‘1’, ‘张磊老师’), (‘2’, ‘李平老师’), (‘3’, ‘刘海燕老师’), (‘4’, ‘朱云海老师’), (‘5’, ‘李杰老师’);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

数据来源:https://www.jianshu.com/p/50c28f721ee5

2.查询“生物”课程比“物理”课程成绩高的所有学生的学号;

SELECT A.student_id FROM
(SELECT * FROM score a,course b WHERE a.course_id=b.cid AND cname=‘生物’) AS A,
(SELECT * FROM score a,course b WHERE a.course_id=b.cid AND cname=‘物理’) AS B
WHERE A.student_id = B.student_id
AND A.num>B.num

思路:先将成绩表和课程表联合,查询学生的生物成绩和物理成绩
SELECT * FROM score a,course b WHERE a.course_id=b.cid AND cname=‘生物’
SELECT * FROM score a,course b WHERE a.course_id=b.cid AND cname=‘物理’
再将这两个查询结果当做两张表,通过学生id联合,并查询“生物成绩表”分数大于“物理成绩表”分数的学生学号

3.查询平均成绩大于60分的同学的学号和平均成绩;

SELECT student_id,AVG(num) FROM score GROUP BY student_id HAVING AVG(num) >60

思路:考察AVG()函数的使用,求平均分可以使用AVG(num),但是这样会算出全班所有学生所有成绩的平均分。
可以通过学生学号分组,就可以查询出每个学生的平均分,SQL中having也是函数中的一种,专门处理在where中无法处理的函数问题。
在本题中,在分组前,无法使用where进行条件约束,所以只能先进行分组,在用having对参数进行约束。

4.查询所有同学的学号、姓名、选课数、总成绩;

SELECT a.student_id,s.sname,a.C,a.S FROM student s,
(SELECT student_id ,COUNT(course_id) AS C,SUM(num) AS S FROM score GROUP BY student_id) AS a
WHERE s.sid=a.student_id

思路:考察使用count()函数和sun()函数,可以先从成绩表中查出学号,选课数,总成绩
SELECT student_id ,COUNT(course_id) AS C,SUM(num) AS S FROM score GROUP BY student_id
再联合学生表加入学生姓名。

5.查询姓“李”的老师的个数;

SELECT COUNT(tid) AS ‘姓李老师的个数’ FROM teacher WHERE tname LIKE’李%’

思路:考察like关键字和%通配符的使用,SQL通配符必须和like关键字一起使用!!

6.查询没学过“李平”老师课的同学的学号、姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sid NOT IN
(SELECT student_id FROM score WHERE course_id IN
(SELECT C.cid FROM teacher AS T,course AS C WHERE T.tid=C.teacher_id AND T.tname=‘李平老师’))

思路:此题思路相对复杂,我们需要先查出名字叫李平的老师都教哪门课程,课程编号是多少
SELECT C.cid FROM teacher AS T,course AS C WHERE T.tid=C.teacher_id AND T.tname=‘李平老师’
题中问的是没学过李平老师所教课程的学生信息,如果我们直接查学生课程编号不存在于李平老师的课程则进入误区,
SELECT student_id FROM score WHERE course_id NOT IN
(SELECT C.cid FROM teacher AS T,course AS C WHERE T.tid=C.teacher_id AND T.tname=‘李平老师’)
这样如果A同学选了2门课,一门是李平老师的,一门不是李平老师的,但因为A同学有一门课不是李平老师的 所以也会被归入答案
所以我们直接查询选择李平老师课程的同学,除去这些同学,剩下的同学就是没有选择李平老师课程的同学
SELECT student_id FROM score WHERE course_id IN
( SELECT C.cid FROM teacher AS T,course AS C WHERE T.tid=C.teacher_id AND T.tname=‘李平老师’)
然后在通过内连接查出学生姓名。

7.查询学过“001”并且也学过编号“002”课程的同学的学号、姓名;

SELECT c.sid,s.sname FROM student AS s,
(SELECT a.student_id AS sid FROM
(SELECT student_id FROM score WHERE course_id=1) AS a,
(SELECT student_id FROM score WHERE course_id=2) AS b
WHERE a.student_id=b.student_id)AS c
WHERE s.sid=c.sid

思路:可以先查出学过001课程的学生和学过002课程的学生,然后取其交集获得学过两门课程的学生学号。
SELECT a.student_id AS sid FROM
(SELECT student_id FROM score WHERE course_id=1) AS a,
(SELECT student_id FROM score WHERE course_id=2) AS b
WHERE a.student_id=b.student_id
然后再通过子查询查出学生姓名。

8.查询学过“李平”老师所教的所有课的同学的学号,姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT DISTINCT student_id FROM score WHERE course_id IN
(SELECT b.cid AS cid FROM teacher AS a,course AS b WHERE a.tid=b.teacher_id AND a.tname=‘李平老师’))

思路:我们可以先查出李平老师教的课程编号,
SELECT b.cid AS cid FROM teacher AS a,course AS b WHERE a.tid=b.teacher_id AND a.tname=‘李平老师’
然后通过成绩表中的学生成绩所属科目找出学李平老师课程的学生学号是多少,
因为李平老师所教课程可能不止一个,所以每个学号出现次数也可能不止一次,要用DISTINCT关键字进行去重
SELECT DISTINCT student_id FROM score WHERE course_id IN
(SELECT b.cid AS cid FROM teacher AS a,course AS b WHERE a.tid=b.teacher_id AND a.tname=‘李平老师’)
最后再结合学生表查出学生姓名。
9.查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号,姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT a.student_id FROM
(SELECT * FROM score WHERE course_id=1) AS a,
(SELECT * FROM score WHERE course_id=2) AS b
WHERE a.student_id = b.student_id
AND a.num > b.num)

思路:此题需要注意一点,查询的是001课程比002课程分数高的学生,所以如果学生只学了其中一门或者一门都没学,不参与查询
先查询学001课程和002课程的学生,再通过内连接筛掉只学了一门的学生,然后比较分数,再联合学生表查出学生姓名即可
10.查询有课程成绩小于60分的同学的学号,姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT DISTINCT student_id FROM score WHERE num<60)

思路:这道题只需注意,有些同学因为不好好学习,挂了很多科,查出学号有多个,需要进行去重。好惨啊…

11.查询没有学全所有课的同学的学号,姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT student_id FROM score GROUP BY student_id HAVING COUNT(student_id) <>
(SELECT COUNT(cid) FROM course))

思路:我们可以先查一共有多少门课程,SELECT COUNT(cid) FROM course
然后我们再通过学生学号对成绩表进行分组,查看学生有几门课程的成绩,也就是他的选课数量
最后添加个having条件,选课数量不等于总数量,也就是没有选全部课程的学生,最终联合学生表查学生姓名即可。

12.查询至少有一门课与学号为“001”的同学所学相同的同学的学号和姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT DISTINCT student_id FROM score WHERE course_id IN
(SELECT course_id FROM score WHERE student_id=1)
AND student_id<>1)

思路:我们先查询学号为001的同学学了哪几门科目,SELECT course_id FROM score WHERE student_id=1
然后再用in关键字,查询那些同学的学科也存在于001同学所选的学科,记得去掉重复学号。
SELECT DISTINCT student_id FROM score WHERE course_id IN
(SELECT course_id FROM score WHERE student_id=1)
最终去掉001同学本身,再联合学生表查出学生姓名。

13.查询至少学过学号为“001”同学所选课程中任意一门课的其他同学学号和姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT DISTINCT student_id FROM score WHERE course_id IN
(SELECT course_id FROM score WHERE student_id=1)
AND student_id<>1)

思路:反复思考题目后,依然觉得与12题问题相同。

14.查询和“002”号的同学学习的课程完全相同的其他同学学号和姓名;

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT student_id FROM score WHERE student_id NOT IN
(SELECT student_id FROM score WHERE course_id NOT IN
(SELECT course_id FROM score WHERE student_id = 2))
AND student_id<>2
GROUP BY student_id
HAVING COUNT(course_id)=(SELECT COUNT(course_id) FROM score WHERE student_id = 2))

思路:此题思路相对复杂,我并没有仔细看网上的答案,不确定自己的SQL是最优解,但可以保证自己的逻辑清晰。
首先我们需要查询学号为002的同学的课程编号 SELECT course_id FROM score WHERE student_id = 2
其次我们可以使用NOT IN关键字 查询出选择了002同学没有选择的课程的同学学号
举个例子:如果有A,B,C,D四门课程,002同学选择了A,B,C 我们就是想查出谁选择了D,因为选择D的人一定不是我们想要的人
SELECT student_id FROM score WHERE course_id NOT IN
(SELECT course_id FROM score WHERE student_id = 2)
然后我们再在分数表中利用NOT IN关键字除去那些我们不想要的人,
SELECT student_id FROM score WHERE student_id NOT IN
(SELECT student_id FROM score WHERE course_id NOT IN
(SELECT course_id FROM score WHERE student_id = 2))
现在查出的学生只是没有选择002同学没选的科目,选择了002同学选择的科目,但不一定全部选择了
题目要求科目完全相同,所以我们还要保证选择的数量的相同的,
要保证这些同学的科目数量和002同学选择的科目数量相同,就要使用count()函数,并且函数结果作为条件,还要用having
最终记得去掉002同学本身,再联合学生表查出学生姓名。
不过,很遗憾,没有和002同学选择完全相同的同学,这个傻屌,选这么多乱七八糟的学科也不怕挂科…

15.删除学习“叶平”老师课的SC表记录

DELETE FROM score WHERE course_id IN
(SELECT cid FROM course AS c,teacher AS t WHERE c.teacher_id=t.tid AND t.tname=‘李平老师’ )

思路:我们可以先查出李平老师教的那些课程的编号,再通过删除where条件删除这些课程编号所处记录

16.向SC表中插入一些记录,这些记录要求符合以下条件:①没有上过编号“002”课程的同学学号;②插入“002”号课程的平均成绩;

INSERT INTO score(student_id,course_id,num)
SELECT a.student_id,2,b.num FROM
(SELECT 1, student_id FROM score WHERE student_id NOT IN (SELECT student_id FROM score WHERE course_id=2)GROUP BY student_id)AS a,
(SELECT 1, AVG(num) AS num FROM score WHERE course_id=2) AS b
WHERE a.1=b.1

思路:这道题是我做到目前为止觉得最有意思的一道题,其实并不难,逻辑也不复杂,
我看了一眼网页上的答案,给的什么玩意儿…所以就全靠秀技术了。
首先我们需要明确一点,向数据库中已有表插入的数据是从其他表中查询出来的格式
INSERT INTO table_name (字段1,字段2,字段3…)select查询语句
需要将select语句查询出来的结果与插入语句结果格式完全相同即可,那么我们开始。
题目第一个要求没上过002课程的同学学号,前面已经练习很多遍,不明确解析这句话。
SELECT student_id FROM score WHERE student_id NOT IN
(SELECT student_id FROM score WHERE course_id=2)GROUP BY student_id
题目第二个要求002课程的平均分,SELECT AVG(num) AS num FROM score WHERE course_id=2
到这里我们已经完成了题目的全部要求,然后我们需要将两个查询结果拼接在一起,
因为没有可以内连接条件,所以我们给两个查询结果都多查出一个字段1,
SQL1:SELECT 1, student_id FROM score WHERE student_id NOT IN
(SELECT student_id FROM score WHERE course_id=2)GROUP BY student_id
SQL2:SELECT 1, AVG(num) AS num FROM score WHERE course_id=2
然后就可以通过内连接将两个查询结果连接起来,完成插入语句。

17.按平均成绩从低到高显示所有学生的“语文”,“数学”,“英语”三门的课程成绩,按如下形式显示:
学生ID,语文,数学,英语,有效课程数,有效平均分;

吐槽:我终于忍不住要吐槽这个题目了,上文的李平老师写成叶平老师我都忍了,
这次让查语文数学英语,你给的数据库数据中哪NMB有语文数学英语??!!
修改题目:按平均成绩从低到高显示所有学生的“生物”,“物理”,“体育”,“美术”四门的课程成绩,按如下形式显示:
学生ID,生物,物理,体育,美术,有效课程数,有效平均分;

SELECT A.sid AS’学生ID’,A.num1 AS’生物’,A.num2 AS ‘物理’,A.num3 AS ‘体育’,E.num AS ‘美术’,A.cou AS’有效课程数’,A.avm AS’有效平均分’ FROM
(SELECT A.sid AS sid,A.cou AS cou,A.avm AS avm ,A.num1 AS num1,A.num2 AS num2 ,D.num AS num3 FROM
(SELECT A.sid AS sid,A.cou AS cou,A.avm AS avm ,A.num1 AS num1,C.num AS num2 FROM
(SELECT A.sid AS sid,A.cou AS cou,A.avm AS avm,B.num AS num1 FROM
(SELECT student_id AS sid,COUNT(course_id) AS cou,AVG(num) AS avm FROM score GROUP BY student_id ) AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘生物’)AS B
ON A.sid=B.sid)AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘物理’)AS C
ON A.sid=C.sid)AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘体育’)AS D
ON A.sid=D.sid)AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘美术’)AS E
ON A.sid=E.sid

思路:emmm,你要是想听,就来找我吧…打字很难说清楚 哈哈哈…

反思:网上给的答案和他自己的问题哪儿都不挨哪儿,但是事后还是给了我一定的启发,然后重新更改SQL:

SELECT A.sid AS’学生ID’,A.num1 AS’生物’,B.num2 AS ‘物理’,C.num3 AS ‘体育’,D.num4 AS ‘美术’,A.cou AS’有效课程数’,A.avm AS’有效平均分’ FROM
(SELECT A.sid AS sid,A.cou AS cou,A.avm AS avm ,B.num AS num1 FROM
(SELECT student_id AS sid,COUNT(course_id) AS cou,AVG(num) AS avm FROM score GROUP BY student_id) AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘生物’)AS B
ON A.sid=B.sid)AS A,
(SELECT A.sid AS sid,B.num AS num2 FROM
(SELECT student_id AS sid,COUNT(course_id) AS cou,AVG(num) AS avm FROM score GROUP BY student_id) AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘物理’)AS B
ON A.sid=B.sid) AS B,
(SELECT A.sid AS sid,B.num AS num3 FROM
(SELECT student_id AS sid,COUNT(course_id) AS cou,AVG(num) AS avm FROM score GROUP BY student_id) AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘体育’)AS B
ON A.sid=B.sid) AS C,
(SELECT A.sid AS sid,B.num AS num4 FROM
(SELECT student_id AS sid,COUNT(course_id) AS cou,AVG(num) AS avm FROM score GROUP BY student_id) AS A LEFT JOIN
(SELECT s.student_id AS sid,s.num FROM course AS c,score AS s WHERE c.cid=s.course_id AND c.cname=‘美术’)AS B
ON A.sid=B.sid) AS D
WHERE A.sid=B.sid
AND A.sid=C.sid
AND A.sid=D.sid

思路:也许你觉得这个答案比上一个还要长,但是这个答案复用性更高,逻辑复杂度相对较低。

18.查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;

SELECT course_id,MAX(num),MIN(num) FROM score GROUP BY course_id

思路:这道题的level一下子就降下来了,主要考max()函数和min()函数的使用。

19.按各科平均成绩从低到高和及格率的百分数从高到低顺序;

平均分:
SELECT course_id FROM score GROUP BY course_id ORDER BY AVG(num)

及格率:
SELECT A.cid FROM
(SELECT course_id AS cid,COUNT(student_id) AS s1 FROM score WHERE num >=60 GROUP BY course_id) AS A,
(SELECT course_id AS cid,COUNT(student_id) AS s2 FROM score GROUP BY course_id) AS B
WHERE A.cid=B.cid
ORDER BY (A.s1/B.s2) DESC

20.课程平均分从高到低显示(显示任课老师);

SELECT b.cname,b.avm,t.tname FROM teacher AS t,
(SELECT c.cname AS cname,c.teacher_id AS tid ,a.avm AS avm FROM course AS c,
(SELECT course_id AS cid,AVG(num) AS avm FROM score GROUP BY course_id ) AS a
WHERE a.cid=c.cid)AS b
WHERE t.tid=b.tid
ORDER BY b.avm DESC

思路:先通过成绩表查出平均分和课程编号,再通过内连接查出编号对应老师编号,最后再连接老师表查出老师姓名。

21.查询各科成绩前三名的记录:(不考虑成绩并列情况)

SELECT c.cname ,
(SELECT num FROM score AS s WHERE s.course_id=c.cid GROUP BY num ORDER BY num DESC LIMIT 0,1) AS 第一,
(SELECT num FROM score AS s WHERE s.course_id=c.cid GROUP BY num ORDER BY num DESC LIMIT 1,1) AS 第二,
(SELECT num FROM score AS s WHERE s.course_id=c.cid GROUP BY num ORDER BY num DESC LIMIT 2,1) AS 第三
FROM course AS c
思路:为什么上一次做到20题就不做了,一方面我确实累了,另一方面21题是真的难,
最终我还是看过答案才写出SQL,实在不太光彩,但是不要紧,学到手才是最重要的。
此题思路十分复杂,首先不要着急写SQL,我们要清楚我们要查的是什么,并且查出来的结果长什么样子。
我们需要查询各科成绩排名前三的成绩,那么查出结果是要么第一行的各列结果信息是科目名,
要么第一行的各列结果信息是第一名,第二名,第三名 只有这两种情况(如果不理解可以问我)。
但是我们知道第一列的数据都是我们写的固定字段,我们写几个字段,SQL就会查几个字段。
那么,在我们只说查询全部科目,不知道有哪些科目的情况下,根本做不到将科目放在第一行的数据头中。
(我就是陷入了这个误区,才会想不清楚,最终屈服,去看答案 -_-||)
所以我们其实只能将第一名 第二名 第三名放在标题头,毕竟题目中给出了查前三名。
但是,即便知道了我们要什么,这道题依然存在难点。
其实第几名并不复杂,我们可以根据分数排序,并且通过分页取任意名次,MySQL的分页更是容易。
SELECT num FROM score GROUP BY num ORDER BY num DESC LIMIT 0,1
##这个SQL相信大家都看得懂 GROUP BY num 只是为了去重,大多数情况下GROUP BY性能更好。
但是我们如何将科目分数很工整的排列在结果中呢?
SELECT * FROM course 这条SQL可以很好的将各科学科的id排列出来。 那我们需要将上面的SQL放入这条SQL的子查询中,就可以将上一条SQL按照科目依次排列出来
SELECT a.*,
(SELECT num FROM score AS s WHERE s.course_id= a.cid ORDER BY num DESC LIMIT 1)
FROM course AS a
这样我们就可以将所有科目的任意名次查询出来,最终我们可以通过SQL分页将所需的全部名次查询出来
其实并不是说这道题逻辑有多难,只不过我之前没有过需要思考查询出来的结果的相关SQL,
所以说这道题还是对我们的SQL题解读面有一个良好的开拓。给这道题点个赞!!

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

SELECT c.cname AS ‘科目’,IFNULL(a.counts,0) AS ‘选课人数’ FROM course AS c LEFT JOIN
(SELECT course_id AS c_id,COUNT(student_id) AS counts FROM score GROUP BY course_id)AS a
ON c.cid = a.c_id

思路:此题相对简单,我们通过count()并且通过科目进行分组就可以求出我们想要的大概的内容,只需再通过左连接将科目名称加上即可
SELECT course_id AS c_id,COUNT(student_id) AS counts FROM score GROUP BY course_id
但是,要注意,只通过分数表一张表决定科目选择人数实在过于草率,你不敢保证会不会有一门科目冷门到根本没有人选择,
所以我们还需要连接课程表,通过将课程表作为主表,确定科目数量,并且通过ifnull()函数将没有选择此科目的null值换成0

23.查询出只选修了一门课程的全部学生的学号和姓名

SELECT score.student_id,student.sname
FROM score ,student
WHERE student.sid=score.student_id
GROUP BY student_id
HAVING COUNT(course_id)=1

思路:emmm,这题应该没啥可说的吧…

24.查询男生、女生的人数

SELECT gender ,COUNT(gender) FROM student GROUP BY gender

思路:这更没意思…

25.查询姓“张”的学生名单

SELECT sname FROM student WHERE sname LIKE’张%’

思路:一题不如一题…

26.查询同名同姓学生名单,并统计同名人数;

SELECT sname, COUNT(sname) FROM student GROUP BY sname HAVING COUNT(sname)>1

思路:说实话,这也没啥可说的。但是因为库里没有重名信息,我特意去看了一眼网页上的答案,小编写SQL还真是随意,都不审题的…

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

SELECT c.cname,AVG(s.num) AS avgs
FROM score AS s ,course AS c
WHERE s.course_id=c.cid
GROUP BY course_id
ORDER BY avgs ,course_id DESC;

思路:排序时,多个条件按照优先级排列在ORDER BY后面即可,用’,'隔开

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

SELECT score.student_id,student.sname,AVG(score.num)
FROM score,student
WHERE score.student_id= student.sid
GROUP BY student_id
HAVING AVG(score.num)>85

思路:略…

29.查询课程名称为“数学”,且分数低于60的学生姓名和分数

吐槽:没有数学,谢谢! 查询课程名称为“物理”,且分数低于60的学生姓名和分数改题目为:

SELECT a.sname,s.num AS nums
FROM score AS s ,student AS a
WHERE s.student_id=a.sid
AND s.course_id=(SELECT cid FROM course WHERE cname=‘物理’)
AND s.num<60

思路:先查询物理科目的课程id,再查询分数表中课程id=物理的课程id的同学的分数,并进行条件筛选。

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

SELECT student.sid,student.sname
FROM score ,student
WHERE score.student_id=student.sid
AND score.course_id = 3
AND score.num>80
思路:先查询编号为003的课程的学生学号,并且在and条件后添加分数大于80
最后通过内连接与学生表连接,查出学生姓名
31.求选了课程的学生人数
SELECT COUNT(DISTINCT student_id) AS ‘选课人数’ FROM score

思路:先通过distinct将选课学生的学号去重,再用count()算出学号数量

32.查询选修“杨艳”老师(这个老师没有,就以张磊老师举例)所授课程的学生中,成绩最高的学生姓名及其成绩;

SELECT student.sname,score.num
FROM score,student
WHERE score.student_id=student.sid
AND course_id IN
(SELECT cid FROM course WHERE teacher_id in
(SELECT tid FROM teacher WHERE tname =‘张磊老师’))
ORDER BY num DESC LIMIT 1;

思路:先查出张磊老师的老师编号,然后用老师编号,在课程表中查出课程标号
再通过课程号在成绩表,求出学生成绩和学生学号,然后再进行条件筛选
最终与学生表连接,查出学生姓名。
但需要注意:我们查张磊老师的编号,再将老师编号作为查询条件时,要使用in
我们不能确定数据库中只有一个张磊老师,更不能 确定张磊老师只教一门课
这里需要注意一下。

33.查询各个课程及相应的选修人数

SELECT course.cname AS 科目,
COUNT(score.student_id) AS 人数
FROM score,course
WHERE score.course_id=course.cid
GROUP BY course_id

思路:根据课程编号分组,再通过count()函数对学生学号计数,
最终通过内连接查出课程名称
34.查询不同课程但成绩相同的学生的学号、课程号、学生成绩

SELECT DISTINCT a.student_id,a.course_id,a.num
FROM score a,score b
WHERE a.student_id <> b.student_id
AND a.num=b.num
AND a.course_id<>b.course_id

思路:这道题其实也是一个我们思考SQL容易有的思维空缺的地方,就是自己和自己连接。首先呢,我们通过题目可以看出,题目要求的字段名全是来自于成绩表,不需要连接其他表,那么其实我们可以通过表自己和自己再次连接就可以查出。
首先我们相查的是学生学号,所以我们要保证学号是不重复的,a.student_id <> b.student_id,其次就是根据题目的要求不同课程的相同成绩,a.num=b.num,a.course_id<>b.course_id其实最终我也是看过答案后才发现,这时候查出来的结果并不是最终成绩,还会有重复的数据出现,最终又给答案加了DISTINCT才能查出最终成绩。

35.查询每门课程成绩最好的前两名

SELECT cname ,
(SELECT num FROM score AS s2 WHERE s2.course_id=a.cid GROUP BY num ORDER BY num DESC LIMIT 0,1) AS 第一名,
(SELECT num FROM score AS s2 WHERE s2.course_id=a.cid GROUP BY num ORDER BY num DESC LIMIT 1,1) AS 第二名
FROM course a

思路:此题思路和21题是相同的,有了21题的铺垫,写这道题就没有那么困难了。

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

SELECT s.sid,FROM student AS s WHERE s.sidIN
(SELECT student_id FROM score GROUP BY student_id HAVING COUNT(course_id)>2 )

思路:我们先查出每个学生选了几门课程,然后进行课程数量筛选条件,然后结合学生表查出学生姓名。

37.查询全部学生都选修的课程的课程号和课程名

SELECT s.sid,s.sname FROM student AS s WHERE s.sidIN
(SELECT student_id FROM score GROUP BY student_id HAVING COUNT(course_id)=(SELECT COUNT(*) FROM course))

思路:我们先要确定一共有多少门课程,然后确定每个学生都修了多少门课程然后进行匹配即可。

38.查询没学过“李平”老师讲授的任一门课程的学生姓名

SELECT sname FROM student WHERE student.sid NOT IN
(SELECT score.student_id FROM teacher,course,score
WHERE teacher.tid=course.teacher_id
AND score.course_id= course.`cid

思路:首先我们先查询李平老师教过的课程,并且通过内连接去连接课程表直接将课程id查出来, 然后我们就可以在成绩表中通过课程id查询都有哪些学生学过李平老师的课,最终查看剩余学生就可以得出答案。
此题与第六题相同但给出了不同的答案,其实都差不多,无可厚非。

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

SELECT student_id,AVG(num) FROM score WHERE num <60
GROUP BY student_id HAVING COUNT(num)>2

思路:先查出不及格的学生和成绩再通过学生id分组,最终求出平均成绩。

40.检索“004”课程分数小于60,按分数降序排列的同学学号

SELECT student_id ,num FROM score WHERE course_id=4
AND num<60 ORDER BY num

思路:先添加where条件后再进行排序。

41.删除“002”同学的“001”课程的成绩

DELETE FROM score WHERE student_id=2 AND course_id=1
SELECT student_id,AVG(num) FROM score WHERE num <60 GROUP BY student_id HAVING COUNT(num)>2

思路:只是简单的删除语句,叠加了删除条件。

祝大家大富大贵,长命百岁

你可能感兴趣的:(SQL)