说到 MySQL 练习题,就不得不提一下这个 MySQL 50 题,文章来源于:https://blog.csdn.net/flycat296/article/details/63681089。
1. 环境
学生表 Student
create table Student(Sid varchar(10),Sname nvarchar(10),Sage datetime,Ssex nvarchar(10));insert into Student values('01' , N'赵雷' , '1990-01-01' , N'男');insert into Student values('02' , N'钱电' , '1990-12-21' , N'男');insert into Student values('03' , N'孙风' , '1990-05-20' , N'男');insert into Student values('04' , N'李云' , '1990-08-06' , N'男');insert into Student values('05' , N'周梅' , '1991-12-01' , N'女');insert into Student values('06' , N'吴兰' , '1992-03-01' , N'女');insert into Student values('07' , N'郑竹' , '1989-07-01' , N'女');insert into Student values('08' , N'王菊' , '1990-01-20' , N'女');
Sid 学生编号 Sname 学生姓名 Sage 出生年月 Ssex 学生性别
科目表 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');
Cid 课程编号 Cname 课程名称 Tid 教师编号
教师表 Teacher
create table Teacher(Tid varchar(10),Tname nvarchar(10))insert into Teacher values('01' , '张三')insert into Teacher values('02' , '李四')insert into Teacher values('03' , '王五')
Tid 教师编号 Tname 教师姓名
成绩表 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);
2. 练习题
1. 查询“01”课程比“02”课程成绩高的学生的信息即课程分数
解题思路:
由于 01 课程和 02 课程是在一张表中不同的行的数据,所以要在一次查询中出现两行数据,就必须要用到子查询了。有了这个思路,接下来的事情就很容易了:
- 主查询:查询学生表的所有字段和课程表的成绩字段,用学生信息表去连成绩表,连表条件为 sc.Sid=stu.Sid;
- 子查询1:查询当前学生的 01 编号的课程成绩
- 子查询2:查询当前学生的 02 编号的课程成绩
筛选:选择 01 课程的成绩大于 02 课程的成绩的学生 ```sql
课程编号为 01 的课程成绩
select sc.score FROM sc WHERE sc.Cid = ‘01’;
课程编号为 02 的课程成绩
select sc.score FROM sc WHERE sc.Cid = ‘02’;
主查询
select stu.*,sc.score FROM student stu left JOIN sc ON stu.Sid = sc.Sid
有了上面这几个查询,最后将其组合起来就可以得到想要的结果了。```sqlselect stu.*,sc.scoreFROM student stuleft JOIN sc ON stu.Sid = sc.SidWHERE (( select sc.score FROM sc WHERE sc.Cid = '01' AND sc.Sid = stu.Sid)>(select sc.scoreFROM scWHERE sc.Cid = '02' AND sc.Sid = stu.Sid));
主查询里面的值,能用到子查询里面, 比如 stu.Sid
效果:
Sid Sname Sage Ssex Ssex score02 钱电 1990-12-21 00:00:00 男 70.002 钱电 1990-12-21 00:00:00 男 60.002 钱电 1990-12-21 00:00:00 男 80.004 李云 1990-08-06 00:00:00 男 50.004 李云 1990-08-06 00:00:00 男 30.004 李云 1990-08-06 00:00:00 男 20.0
借鉴别人的方案:
select a.*, b.*, c.* from
(select * from sc where Cid = '01') a
left join (select * from sc where Cid = '02') b
on a.Sid = b.Sid
left join student c
on a.Sid = c.Sid
where a.score > b.score;
总结:
- 查询同一个表的多行的数据在同一行展示的时候,一次查询肯定实现不了,此时就需要多次查询,而多次查询就必须要使用到子查询。
- 应该尽量将同属于一个主体的数据在一行中展示,所以从这里来看,我的
1.1 查询同时存在 “01”课程和“02”课程的情况
解题思路:
同时是关键,可以利用连表时对于没有的数据会显示空的特性,可以利用这个来确定。看了别人的 sql ,所以决定基于别人的 sql。
步骤:
- 先建立子查询,查询编号为 01 的所有课程和 02 的所有课程
- 然后用 studet 表去连接这两张表虚拟表,筛选掉其中有空的情况
SELECT stu.*,a.*,b.* FROM student stu LEFT JOIN (SELECT * FROM sc WHERE Cid = '01') a ON stu.Sid = a.Sid LEFT JOIN (SELECT * FROM sc WHERE Cid = '02') b ON stu.Sid = b.Sid WHERE a.Sid IS NOT NULL AND b.Sid IS NOT NULL;1.2 查询存在“01”课程,但可能不存在“02”课程的情况
解题思路:
题目中的关键就在于,可能不存在。既然可能不存在,那“02”课程的存在与否就不是题目的关键了,所以不用加条件去限制“02”课程出现的情况。而是保证“01”课程的存在即可SELECT stu.*,a.*,b.* FROM student stu LEFT JOIN (SELECT * FROM sc WHERE Cid = '01') a ON stu.Sid = a.Sid LEFT JOIN (SELECT * FROM sc WHERE Cid = '02') b ON stu.Sid = b.Sid WHERE a.Sid IS NOT NULL;1.3 查询不存在“01”课程,但存在“02”课程的情况
这道题和前面的差不多
2. 查询成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
解题思路:
查询列表有:学生编号、学生姓名,这个都属于一行数据,但是平均成绩是多行成绩,因此必须要用到子查询才可以。然后再筛选掉低于 60 分的同学就可以了。
SELECT stu.Sid,stu.Sname,IFNULL(a.avg_score,0)
FROM student stu
LEFT JOIN (SELECT Sid,avg(score) AS avg_score FROM sc GROUP BY Sid) a ON a.Sid = stu.Sid;
WHERE a.avg_score>=60;
3. 查询在 SC 表存在成绩的学生的信息
解题思路:
根据Sid进行连表查询,判断连表结果不为空的
SELECT DISTINCT st.*
FROM student st
LEFT JOIN sc ON sc.Sid = st.Sid
WHERE sc.Cid IS NOT NULL;
结果没有什么问题,不过看了别人写的 sql,对比我自己的来说,见解要更深刻一点。取两个表种都存在的数据,直接使用内连接查询即可,因为内连接的结果是两个集合的交集部分。
92语法:
SELECT DISTINCT st.*
FROM student st,sc
WHERE st.Sid=sc.Sid;
99语法:
SELECT DISTINCT st.*
FROM student st
INNER JOIN sc ON st.Sid=sc.Sid;
4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
SELECT student.Sid,student.Sname,COUNT(sc.Sid) AS '选课总数',SUM(sc.score) AS '课程总成绩'
FROM student
LEFT JOIN sc ON sc.Sid = student.Sid
GROUP BY sc.Sid;
5. 查询「李」姓老师的数量
SELECT COUNT(teacher.Tid)
FROM teacher
WHERE teacher.Tname LIKE "李%";
