说到 MySQL 练习题,就不得不提一下这个 MySQL 50 题,文章来源于:https://blog.csdn.net/flycat296/article/details/63681089

1. 环境


学生表 Student

  1. create table Student(Sid varchar(10),Sname nvarchar(10),Sage datetime,Ssex nvarchar(10));
  2. insert into Student values('01' , N'赵雷' , '1990-01-01' , N'男');
  3. insert into Student values('02' , N'钱电' , '1990-12-21' , N'男');
  4. insert into Student values('03' , N'孙风' , '1990-05-20' , N'男');
  5. insert into Student values('04' , N'李云' , '1990-08-06' , N'男');
  6. insert into Student values('05' , N'周梅' , '1991-12-01' , N'女');
  7. insert into Student values('06' , N'吴兰' , '1992-03-01' , N'女');
  8. insert into Student values('07' , N'郑竹' , '1989-07-01' , N'女');
  9. insert into Student values('08' , N'王菊' , '1990-01-20' , N'女');

Sid 学生编号 Sname 学生姓名 Sage 出生年月 Ssex 学生性别

科目表 Course

  1. create table Course(Cid varchar(10),Cname nvarchar(10),Tid varchar(10));
  2. insert into Course values('01' , '语文' , '02');
  3. insert into Course values('02' , '数学' , '01');
  4. insert into Course values('03' , '英语' , '03');

Cid 课程编号 Cname 课程名称 Tid 教师编号

教师表 Teacher

  1. create table Teacher(Tid varchar(10),Tname nvarchar(10))
  2. insert into Teacher values('01' , '张三')
  3. insert into Teacher values('02' , '李四')
  4. insert into Teacher values('03' , '王五')

Tid 教师编号 Tname 教师姓名

成绩表 SC

  1. create table SC(Sid varchar(10),Cid varchar(10),score decimal(18,1));
  2. insert into SC values('01' , '01' , 80);
  3. insert into SC values('01' , '02' , 90);
  4. insert into SC values('01' , '03' , 99);
  5. insert into SC values('02' , '01' , 70);
  6. insert into SC values('02' , '02' , 60);
  7. insert into SC values('02' , '03' , 80);
  8. insert into SC values('03' , '01' , 80);
  9. insert into SC values('03' , '02' , 80);
  10. insert into SC values('03' , '03' , 80);
  11. insert into SC values('04' , '01' , 50);
  12. insert into SC values('04' , '02' , 30);
  13. insert into SC values('04' , '03' , 20);
  14. insert into SC values('05' , '01' , 76);
  15. insert into SC values('05' , '02' , 87);
  16. insert into SC values('06' , '01' , 31);
  17. insert into SC values('06' , '03' , 34);
  18. insert into SC values('07' , '02' , 89);
  19. 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

  1. 有了上面这几个查询,最后将其组合起来就可以得到想要的结果了。
  2. ```sql
  3. select stu.*,sc.score
  4. FROM student stu
  5. left JOIN sc ON stu.Sid = sc.Sid
  6. WHERE (
  7. ( select sc.score FROM sc WHERE sc.Cid = '01' AND sc.Sid = stu.Sid)
  8. >
  9. (select sc.scoreFROM scWHERE sc.Cid = '02' AND sc.Sid = stu.Sid)
  10. );

主查询里面的值,能用到子查询里面, 比如 stu.Sid

效果:

  1. Sid Sname Sage Ssex Ssex score
  2. 02 钱电 1990-12-21 00:00:00 70.0
  3. 02 钱电 1990-12-21 00:00:00 60.0
  4. 02 钱电 1990-12-21 00:00:00 80.0
  5. 04 李云 1990-08-06 00:00:00 50.0
  6. 04 李云 1990-08-06 00:00:00 30.0
  7. 04 李云 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. 查询同一个表的多行的数据在同一行展示的时候,一次查询肯定实现不了,此时就需要多次查询,而多次查询就必须要使用到子查询。
  2. 应该尽量将同属于一个主体的数据在一行中展示,所以从这里来看,我的

    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 "李%";

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