【0928 | Day 39】三大范式/数据库查询练习

一、数据库的三大设计范式

1. 第一范式:数据中所有字段都是不可分割的原子值

倘若字段可以继续拆分,就不满足第一范式,举个例子:

==》创建一个表student2,再向里面插入数据,结果如下

mysql> select * from student2;
+----+--------+-----------------------------+
| id | name   | address                     |
+----+--------+-----------------------------+
|  1 | 张三   | 安徽省合肥市蜀山区          |
|  2 | 李四   | 安徽省合肥市庐阳区          |
|  3 | 王二   | 安徽省合肥市包河区          |
+----+--------+-----------------------------+

3 rows in set (0.11 sec)

分析:其实还是可以拆分的可以再分成省份、城市、区,上图就是可拆分,不满足第一范式。我们要把表拆的详细一点,后期方便统计。

注意:范式设计的越详细,对某些实际操作可能更好,但是不一定都是好处。

2. 第二范式:必须满足第一范式的前提下,第二范式要求,除主键外的每一列都必须完全依赖于主键

如果出现不完全依赖,只可能发送在联合主键的情况下。
==》下面我们创建一个表,用来当做订单

mysql> create table myorser(
    -> product_id int,           #产品号
    -> customer_id int,          #用户号
    -> product_name varchar(20),
    -> customer_name varchar(20),
    -> primary key(product_id,customer_id)     #产品号和用户号形成联合主键
    -> );
    
Query OK, 0 rows affected (1.21 sec)

分析:除主键外其他列,只依赖于主键的部分字段。产品的名字只和产品号有关、用户的名字只和用户号有关,就是不完全依赖于主键,比满足第二范式!!
  

解决方法如下,拆表:

mysql> create table myorder2(     #订单id表
    -> order_id int primary key,
    -> product_id int,
    -> customer_id int
    -> );
    
Query OK, 0 rows affected (0.99 sec)

mysql> create table product(    #产品名表,依赖于产品id
    -> id int primary key,
    -> name varchar(20)
    -> );
    
Query OK, 0 rows affected (0.93 sec)

mysql> create table customer(   #顾客名表,依赖于顾客id
    -> id int primary key,
    -> name varchar(20)
    -> );
    
Query OK, 0 rows affected (0.82 sec)

3. 第三范式:必须满足第二范式,除主键列的其他列之间不能有传递依赖关系

==》看这个例子:

mysql> create table myorder2(    
    -> order_id int primary key,
    -> product_id int,
    -> customer_id int,
    -> customer_phone varchar(20)
    -> );
    
Query OK, 0 rows affected (0.99 sec)

分析:这里相比上面订单id表,多了一个顾客手机,很明显customer_phone和order_id主键有关系,但是customer_phone还依赖于customer_id(除主键外的其他键)。这就不满足第三范式了,应该将顾客的手机放入顾客表中才满足第三范式。

二、查询练习

1. 准备

==》准备创建几个表:

  • 学生表(Student):学号、姓名、性别、出生年月日、班级
  • 课程表(Course):课程号、课程名称、教师编号
  • 成绩表(Score) :学号、课程号、成绩
  • 教师表(Teacher):教师编号、教师性别、教师性别、出生年月日、职称、所在部门
#创建一个test2新数据库
mysql> create database `test2` character set utf8;    
Query OK, 1 row affected, 1 warning (0.67 sec)

#创建学生表
mysql> create table student(        
    -> snumber varchar(20) primary key,
    -> sname varchar(20) not null,
    -> ssex varchar(20) not null,
    -> sbirthday datetime,
    -> class varchar(20)
    -> );
    
Query OK, 0 rows affected (1.06 sec)

#创建老师表
mysql> create table teacher(
    -> tnumber varchar(20) primary key,
    -> tname varchar(20) not null,
    -> tsex varchar(20) not null,
    -> tbirthday datetime,
    -> prof varchar(20) not null,
    -> depart varchar(20) not null
    -> );
    
Query OK, 0 rows affected (0.88 sec)

#创建课程表
mysql> create table course(
    -> cnumber varchar(20) primary key,
    -> cname varchar(20) not null,
    -> tnumber varchar(20) not null,
       #其中tnumber和老师表中的tnumber一样,使用外键
    -> foreign key(tnumber) references teacher(tnumber) 
    -> );
    
Query OK, 0 rows affected (1.02 sec)

#创建成绩表
mysql> create table score(
    -> snumber varchar(20) not null,
    -> cnumber varchar(20) not null,
    -> degree decimal,
    -> foreign key(snumber) references student(snumber),
    -> foreign key(cnumber) references course(cnumber),
       #一个联合主键,学生号和课程号不重复就好
    -> primary key(snumber,cnumber) 
    -> );
    
Query OK, 0 rows affected (1.01 sec)

2. 导入数据

mysql> select * from student;
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 102     | 王二      | 女   | 1999-09-23 00:00:00 | 一班   |
| 103     | 王尼玛    | 男   | 1988-01-11 00:00:00 | 一班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
+---------+-----------+------+---------------------+--------+
7 rows in set (0.00 sec)

mysql> select * from teacher;
+---------+--------+------+---------------------+-----------+-----------------+
| tnumber | tname  | tsex | tbirthday           | prof      | depart          |
+---------+--------+------+---------------------+-----------+-----------------+
| 111     | 古一   | 女   | 0000-01-01 00:00:00 | 教授      | 化学系          |
| 112     | 王     | 男   | 2000-09-03 00:00:00 | 副教授    | 计算机系        |
| 113     | 春丽   | 女   | 1988-11-05 00:00:00 | 助教      | 英语系          |
| 114     | 刘邦   | 男   | 1978-12-03 00:00:00 | 助教      | 通信工程系      |
+---------+--------+------+---------------------+-----------+-----------------+
4 rows in set (0.00 sec)

mysql> select * from course;
+---------+--------------+---------+
| cnumber | cname        | tnumber |
+---------+--------------+---------+
| 3-105   | 数据结构     | 112     |
| 3-245   | 模拟电路     | 113     |
| 6-166   | 人工智能     | 111     |
| 9-888   | 数字电路     | 114     |
+---------+--------------+---------+
4 rows in set (0.00 sec)

mysql> select * from score;
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 100     | 3-245   |     85 |
| 101     | 3-245   |     95 |
| 102     | 3-105   |     83 |
| 103     | 3-105   |     89 |
| 104     | 3-245   |     66 |
| 105     | 6-166   |     60 |
| 106     | 6-166   |     92 |
+---------+---------+--------+
7 rows in set (0.00 sec)

3. 练习

1)

  • 查询student表中的所有记录
  • 用法:mysql> select * from  student;
mysql> select * from student;
# 其中 * 表示所有字段的意思

+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 102     | 王二      | 女   | 1999-09-23 00:00:00 | 一班   |
| 103     | 王尼玛    | 男   | 1988-01-11 00:00:00 | 一班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
+---------+-----------+------+---------------------+--------+
7 rows in set (0.00 sec)

2)

  • 查询student表中所有记录的sname、ssex、class列
  • 用法:mysql> select + 要查询的列(多个用逗号隔开) + from + 表名;
mysql> select sname,ssex,class from student;
+-----------+------+--------+
| sname     | ssex | class  |
+-----------+------+--------+
| 张三      | 男   | 一班   |
| 李四      | 男   | 一班   |
| 王二      | 女   | 一班   |
| 王尼玛    | 男   | 一班   |
| 张全蛋    | 男   | 一班   |
| 赵铁柱    | 男   | 二班   |
| 木子      | 女   | 二班   |
+-----------+------+--------+
7 rows in set (0.00 sec)

3)

  • 查询教师的所有单位,即不重复的depart列
  • 用法:mysql> select distinct depart from teacher;
mysql> select depart from teacher;
+-----------------+
| depart          |
+-----------------+
| 化学系          |
| 计算机系        |
| 通信工程系      |
| 通信工程系      |
+-----------------+
4 rows in set (0.00 sec)


mysql> select distinct depart from teacher;
+-----------------+
| depart          |
+-----------------+
| 化学系          |
| 计算机系        |
| 通信工程系      |
+-----------------+
3 rows in set (0.10 sec)

4)

  • 查询score表中成绩 60到90 之间的所有记录
  • 用法一:mysql> select * from score where degree between 60 and 80;(between包括端点值)
  • 用法二:mysql> select * from score where degree >= 60 and degree<= 90;
mysql> select * from score where degree between 60 and 90;
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 100     | 3-245   |     85 |
| 102     | 3-105   |     83 |
| 103     | 3-105   |     89 |
| 104     | 3-245   |     66 |
| 105     | 6-166   |     60 |
+---------+---------+--------+
5 rows in set (0.00 sec)

5)

  • 查询score表中85、95或83的记录
  • 用法:in
mysql> select * from score where degree in (85,95,83);
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 100     | 3-245   |     85 |
| 101     | 3-245   |     95 |
| 102     | 3-105   |     83 |
+---------+---------+--------+
3 rows in set (0.00 sec)

6)

  • 查询student表中班级为一班或性别为女的同学记录
  • 用法:or
mysql> select * from student where class='一班' or ssex='女';
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 100     | 张三       | 男   | 1999-09-01 00:00:00 | 一班   |
| 101     | 李四       | 男   | 1999-02-11 00:00:00 | 一班   |
| 102     | 王二       | 女   | 1999-09-23 00:00:00 | 一班   |
| 103     | 王尼玛     | 男   | 1988-01-11 00:00:00 | 一班   |
| 104     | 张全蛋     | 男   | 2000-09-03 00:00:00 | 一班   |
| 106     | 木子       | 女   | 2000-12-16 00:00:00 | 二班   |
+---------+-----------+------+---------------------+--------+
6 rows in set (0.00 sec)

7)

  • 按照学号(snumber)升序降序的方式查询student表中的记录
  • 用法(降序):mysql> select * from student order by snumber(什么字段) desc(降序);
  • 用法一(升序):mysql> select * from student order by snumber(什么字段) asc(升序);
  • 用法二(升序):mysql> select * from student order by snumber;(升序两种方式一样)
mysql> select * from student order by snumber desc;
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
| 103     | 王尼玛    | 男   | 1988-01-11 00:00:00 | 一班   |
| 102     | 王二      | 女   | 1999-09-23 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
+---------+-----------+------+---------------------+--------+

7 rows in set (0.00 sec)

8)

  • 按照教师号(cnumber)升序、成绩(degree)降序查询score表中的记录
  • 用法:mysql> select * from score order by cnumber asc ,degree desc;
ysql> select * from score order by cnumber asc ,degree desc;
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 103     | 3-105   |     89 |
| 102     | 3-105   |     83 |
| 101     | 3-245   |     95 |
| 100     | 3-245   |     85 |
| 104     | 3-245   |     66 |
| 106     | 6-166   |     92 |
| 105     | 6-166   |     60 |
+---------+---------+--------+
7 rows in set (0.00 sec)

分析:这条语句会先按照教师号升序排列,遇到相同的教师号再按照成绩降序进行排列(order by 先按照第一个排,再考虑第二个排列)

注意:当两个同时排序的话,asc(升序)必须要写(sql8.0不写也没事)

9)

  • 查询一班的人数
  • 用法:count
mysql> select count(*) from student where class='一班';
+----------+
| count(*) |
+----------+
|        5 |
+----------+
1 row in set (0.15 sec)

10)

  • 查询score表中最高分的学生学号和课程号
  • 用法:mysql> select snumber,cnumber from score where degree=(select max(degree) from score);
mysql> select snumber,cnumber from score where degree=(select max(degree) from score);
+---------+---------+
| snumber | cnumber |
+---------+---------+
| 101     | 3-245   |
+---------+---------+
1 row in set (0.35 sec)

对于这个复合语句进行拆分:

  1. 找到最高分
    select max(degree) from score
  2. 找到最高分的学号和课程号
    mysql> select snumber,cnumber from score where degree=(select max(degree) from score);

11)

  • 排序的做法

  • 用法:mysql> select snumber,cnumber,degree from score order by degree desc limit 0,1;

mysql> select snumber,cnumber,degree from score order by degree desc  limit 0,1;
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 101     | 3-245   |     95 |
+---------+---------+--------+
1 row in set (0.00 sec)

分析:这里的 limit 0,1** 表示取表中从第0条取到第一条(也就是取出第一条数据)

注意:limit 的第一个数字表示从哪里开始查,第二个数字表示查几条

12)

  • 查询每门课的平均成绩
  • 用法:avg(degree)
mysql> select * from course;
+---------+--------------+---------+
| cnumber | cname        | tnumber |
+---------+--------------+---------+
| 3-105   | 数据结构     | 112     |
| 3-245   | 模拟电路     | 113     |
| 6-166   | 人工智能     | 111     |
| 9-888   | 数字电路     | 114     |
+---------+--------------+---------+
4 rows in set (0.00 sec)
  • 查询3-105老师带的数据结构这门课的平均成绩
#先看一下这门课的学生所有成绩
mysql> select degree from score where cnumber='3-105';
+--------+
| degree |
+--------+
|     83 |
|     89 |
+--------+
2 rows in set (0.11 sec)

#计算平均成绩
mysql> select avg(degree) from score where cnumber='3-105';
+-------------+
| avg(degree) |
+-------------+
|     86.0000 |
+-------------+
1 row in set (0.02 sec)
  • 但是我们这只计算了一门,怎么计算每一门呢?一条一条语句的写是可以的,但是比较麻烦,下面写在一条语句中:
  • 用法: group by ,先把课程号分组再进行计算
mysql> select cnumber,avg(degree) from score group by cnumber;
+---------+-------------+
| cnumber | avg(degree) |
+---------+-------------+
| 3-105   |     86.0000 |
| 3-245   |     82.0000 |
| 6-166   |     76.0000 |
+---------+-------------+
3 rows in set (0.00 sec)

13)

  • 查询score表中至少有两名学生选修,并以3开头的课程平均成绩(分组条件与模糊查询)

  • 用法:group by + having + 条件(分组后跟条件要使用having)

==》第一步:score表中至少有两名学生选修

mysql> select cnumber from score 
    ->  group by cnumber  #分组
    -> having count(cnumber)>=2; #条件
+---------+
| cnumber |
+---------+
| 3-105   |
| 3-245   |
| 6-166   |
+---------+
3 rows in set (0.00 sec)

mysql> select cnumber from score group by cnumber
    -> having count(cnumber)>=4;#条件
Empty set (0.00 sec)

问题:有个疑问,为什么要count(cnumber)?

  • 因为这里cnumber是课程号,count是求和关键字,score表中课程数大于等于2的就是至少两人选的课程

注意:以3开头,这里可以用 模糊查询(使用 like)

==》第二步:以3开头的课程平均成绩

mysql> select cnumber from score group by cnumber
    -> having count(cnumber)>=2 and cnumber like '3%'; 
               #3%表示以3开头, %为3后面的任意匹配
+---------+
| cnumber |
+---------+
| 3-105   |
| 3-245   |
+---------+
2 rows in set (0.35 sec)

==》第三步:计算平均值和这门课的人数

mysql> select cnumber,avg(degree),count(*) from score group by cnumber
    -> having count(cnumber)>=2 and cnumber like '3%';
+---------+-------------+----------+
| cnumber | avg(degree) | count(*) |
+---------+-------------+----------+
| 3-105   |     86.0000 |        2 |
| 3-245   |     82.0000 |        3 |
+---------+-------------+----------+
2 rows in set (0.00 sec)

14)

  • 查询成绩大于70,小于90的列
  • 用法一:where + 条件
mysql> select snumber,degree from score
    -> where degree>70 and degree<90;
+---------+--------+
| snumber | degree |
+---------+--------+
| 100     |     85 |
| 102     |     83 |
| 103     |     89 |
+---------+--------+
3 rows in set (0.00 sec)
  • 用法二:between...and...
mysql> select snumber,degree from score
    -> where degree between 70 and 90;

15)

  • 查询所有学生的sname、cnumber、degree(多表查询)
  • 当要查询的内容不在一张表中时,我们可以分开查询,但是太麻烦了。

==》第一步:多表查询

mysql> select snumber,cnumber,degree from score;
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 100     | 3-245   |     85 |
| 101     | 3-245   |     95 |
| 102     | 3-105   |     83 |
| 103     | 3-105   |     89 |
| 104     | 3-245   |     66 |
| 105     | 6-166   |     60 |
| 106     | 6-166   |     92 |
+---------+---------+--------+
7 rows in set (0.00 sec)

mysql> select snumber,sname from student;
+---------+-----------+
| snumber | sname     |
+---------+-----------+
| 100     | 张三      |
| 101     | 李四      |
| 102     | 王二      |
| 103     | 王尼玛    |
| 104     | 张全蛋    |
| 105     | 赵铁柱    |
| 106     | 木子      |
+---------+-----------+
7 rows in set (0.00 sec)

==》第二步:把score表中snumber替换成对应的姓名sname

mysql> select sname,cnumber,degree from student,score
    -> where student.snumber=score.snumber;  #加上限制条件,不然会乱
+-----------+---------+--------+
| sname     | cnumber | degree |
+-----------+---------+--------+
| 张三      | 3-245   |     85 |
| 李四      | 3-245   |     95 |
| 王二      | 3-105   |     83 |
| 王尼玛    | 3-105   |     89 |
| 张全蛋    | 3-245   |     66 |
| 赵铁柱    | 6-166   |     60 |
| 木子      | 6-166   |     92 |
+-----------+---------+--------+
7 rows in set (0.00 sec)

16)

  • 查询所有学生的snumber、cname、degree(多表查询)

==》第一步:先查询一下这两个表中的内容

mysql> select * from score;
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 100     | 3-245   |     85 |
| 101     | 3-245   |     95 |
| 102     | 3-105   |     83 |
| 103     | 3-105   |     89 |
| 104     | 3-245   |     66 |
| 105     | 6-166   |     60 |
| 106     | 6-166   |     92 |
+---------+---------+--------+
7 rows in set (0.00 sec)

mysql> select * from course;
+---------+--------------+---------+
| cnumber | cname        | tnumber |
+---------+--------------+---------+
| 3-105   | 数据结构     | 112     |
| 3-245   | 模拟电路     | 113     |
| 6-166   | 人工智能     | 111     |
| 9-888   | 数字电路     | 114     |
+---------+--------------+---------+
4 rows in set (0.00 sec)

==》第二步:cnumber是一样的,通过这个来写条件

mysql> select cname,snumber,degree from score,course
    -> where score.cnumber=course.cnumber;
+--------------+---------+--------+
| cname        | snumber | degree |
+--------------+---------+--------+
| 模拟电路     | 100     |     85 |
| 模拟电路     | 101     |     95 |
| 数据结构     | 102     |     83 |
| 数据结构     | 103     |     89 |
| 模拟电路     | 104     |     66 |
| 人工智能     | 105     |     60 |
| 人工智能     | 106     |     92 |
+--------------+---------+--------+
7 rows in set (0.00 sec)

17)

  • 查询所有学生的cname、sname,degree(三表关联查询)

==》第一步:找两两之间的相同之处,写条件

mysql> select sname,cname,degree from student,course,score #三个数据来自三个表
    -> where student.snumber=score.snumber  #利用score表中的重复字段来查询
    ->and course.cnumber=score.cnumber;
+-----------+--------------+--------+
| sname     | cname        | degree |
+-----------+--------------+--------+
| 张三      | 模拟电路     |     85 |
| 李四      | 模拟电路     |     95 |
| 王二      | 数据结构     |     83 |
| 王尼玛    | 数据结构     |     89 |
| 张全蛋    | 模拟电路     |     66 |
| 赵铁柱    | 人工智能     |     60 |
| 木子      | 人工智能     |     92 |
+-----------+--------------+--------+
7 rows in set (0.00 sec)

==》第二步:再查询下cnumber和snumber

mysql> select sname,cname,degree,student.snumber,course.cnumber from student,course,score
    -> where student.snumber=score.snumber and course.cnumber=score.cnumber;
+-----------+--------------+--------+---------+---------+
| sname     | cname        | degree | snumber | cnumber |
+-----------+--------------+--------+---------+---------+
| 张三      | 模拟电路     |     85 | 100     | 3-245   |
| 李四      | 模拟电路     |     95 | 101     | 3-245   |
| 王二      | 数据结构     |     83 | 102     | 3-105   |
| 王尼玛    | 数据结构     |     89 | 103     | 3-105   |
| 张全蛋    | 模拟电路     |     66 | 104     | 3-245   |
| 赵铁柱    | 人工智能     |     60 | 105     | 6-166   |
| 木子      | 人工智能     |     92 | 106     | 6-166   |
+-----------+--------------+--------+---------+---------+
7 rows in set (0.00 sec)

注意:这里要查询的snumber和cnumber都加了条件。

  • 因为这两个数据出现在多个表中,如果不指定电脑不知道找哪一个表中的(尽管都相同),但是会报错:
    ERROR 1052 (23000): Column 'snumber' in field list is ambiguous

我们可以验证一下:

mysql> select sname,cname,degree,student.snumber as stu_num,score.snumber ,course.cnumber from student,course,score
    -> where student.snumber=score.snumber and course.cnumber=score.cnumber;
+-----------+--------------+--------+---------+---------+---------+
| sname     | cname        | degree | stu_num | snumber | cnumber |
+-----------+--------------+--------+---------+---------+---------+
| 张三      | 模拟电路     |     85 | 100     | 100     | 3-245   |
| 李四      | 模拟电路     |     95 | 101     | 101     | 3-245   |
| 王二      | 数据结构     |     83 | 102     | 102     | 3-105   |
| 王尼玛    | 数据结构     |     89 | 103     | 103     | 3-105   |
| 张全蛋    | 模拟电路     |     66 | 104     | 104     | 3-245   |
| 赵铁柱    | 人工智能     |     60 | 105     | 105     | 6-166   |
| 木子      | 人工智能     |     92 | 106     | 106     | 6-166   |
+-----------+--------------+--------+---------+---------+---------+
7 rows in set (0.00 sec)

其中的student.snumber as stu_num可以给要显示的列进行更名,但是仅仅局限于此次查询。通过结果可发现结果是相同的

18)

  • 查询一班学生每门课的平均成绩

==》第一步:

mysql> select avg(degree) from score
          where snumber in (select snumber from student where class='一班');
+-------------+
| avg(degree) |
+-------------+
|     83.6000 |
+-------------+
1 row in set (0.18 sec)

但是这是所有课程的平均成绩,我们要求的是每门课的平均成绩,其实就是按照老师号进行分组即可 group by cnumber

mysql> select cnumber, avg(degree) from score where snumber in (select snumber from student where class='一班')
    -> group by cnumber;  #按照老师号进行分组
+---------+-------------+
| cnumber | avg(degree) |
+---------+-------------+
| 3-245   |     82.0000 |
| 3-105   |     86.0000 |
+---------+-------------+
2 rows in set (0.16 sec)

19)

  • 查询选修‘3-105’课程中成绩高于102号同学成绩的同学记录(子查询)

==》第一步:先把102号同学的3-105课程的成绩导出来,用到了and(同时)

mysql> select degree from score where snumber='102' and cnumber='3-105';
+--------+
| degree |
+--------+
|     83 |
+--------+
1 row in set (0.00 sec)

==》再加一个3-105课程就可以筛选出来

mysql> select snumber,degree from score where
     #成绩条件
    -> degree>(select degree from score where snumber='102' and cnumber='3-105')   
     #课程号条件
    -> and cnumber='3-105'; 
+---------+--------+
| snumber | degree |
+---------+--------+
| 103     |     89 |
+---------+--------+
1 row in set (0.03 sec)

20)

  • 查询所有课程的成绩高于‘3-105’课程中成绩高于102号同学成绩的同学记录
mysql> select snumber,degree from score where
    -> degree>(select degree from score where snumber='102' and cnumber='3-105');
+---------+--------+
| snumber | degree |
+---------+--------+
| 100     |     85 |
| 101     |     95 |
| 103     |     89 |
| 106     |     92 |
+---------+--------+
4 rows in set (0.00 sec)

21)

  • 查询学号为100、104 的同学同年出生的所有学生的snumber、sname和sbirthday

==》第一步:先看一眼student表

mysql> select * from student;
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 102     | 王二      | 女   | 1999-09-23 00:00:00 | 一班   |
| 103     | 王尼玛    | 男   | 1988-01-11 00:00:00 | 一班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
+---------+-----------+------+---------------------+--------+
7 rows in set (0.00 sec)

==》第二步:通过year()函数

mysql> select year(sbirthday) from student where snumber in (100,104);
+-----------------+
| year(sbirthday) |
+-----------------+
|            1999 |
|            2000 |
+-----------------+
2 rows in set (0.04 sec)

==》第三步:有了年份,就可以进行筛选了,注意这里不能用 = 来做条件因为这里的年份是两个值,应该用 in,有一个条件用 =,两个以上条件用 in

mysql> select snumber,sname,sbirthday from student
  -> where year(sbirthday) in (select year(sbirthday) from student where snumber in (100,104));
+---------+-----------+---------------------+
| snumber | sname     | sbirthday           |
+---------+-----------+---------------------+
| 100     | 张三      | 1999-09-01 00:00:00 |
| 101     | 李四      | 1999-02-11 00:00:00 |
| 102     | 王二      | 1999-09-23 00:00:00 |
| 104     | 张全蛋    | 2000-09-03 00:00:00 |
| 106     | 木子      | 2000-12-16 00:00:00 |
+---------+-----------+---------------------+
5 rows in set (0.04 sec)

22)

  • 查询‘古一’老师任课的学生成绩(多层嵌套子查询)

==》第一步:先看一下古一的个人信息

mysql> select * from teacher where tname='古一';
+---------+--------+------+---------------------+--------+-----------+
| tnumber | tname  | tsex | tbirthday           | prof   | depart    |
+---------+--------+------+---------------------+--------+-----------+
| 111     | 古一   | 女   | 0000-01-01 00:00:00 | 教授   | 化学系    |
+---------+--------+------+---------------------+--------+-----------+
1 row in set (0.00 sec)

==》第二步:从这个表中得到古一的tnumber,再根据tnumner在course表中找到她教的课程的cnumber号

mysql> select cnumber from course 
     > where tnumber=(select tnumber from teacher where tname='古一');
+---------+
| cnumber |
+---------+
| 6-166   |
+---------+
1 row in set (0.00 sec)

==》第三步:知道了cnumber号就可以从score表中得到她教这门课的平均成绩了

mysql> select avg(degree) from score
    -> where cnumber=( select cnumber from course 
    -> where tnumber=(select tnumber from teacher where tname='古一') );
+-------------+
| avg(degree) |
+-------------+
|     76.0000 |
+-------------+
1 row in set (0.01 sec)

总结:多层嵌套的子查询,查询结果作为另一个的条件

23)

  • 查询选修某门课人数多于2人的教师姓名
  • 先查询人数多于2人的课程号,再查询老师的tnumber,再查询老师的姓名,步步嵌套
mysql> select tname from teacher
    #条件3:以条件2查找老师的名字
    -> where tnumber = 
    #条件2:以条件1位条件找到 老师的tnumber,
    ->(select tnumber from course  where cnumber=
    #条件1:人数多于2人的课程号
    -> ( select cnumber from score  group by cnumber having count(*)>2 ) );
+--------+
| tname  |
+--------+
| 春丽   |
+--------+
1 row in set (0.00 sec)

24)

  • 查询一班二班全体学生记录
  • 用法:in
mysql> select * from student where class in ('一班','二班');
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 102     | 王二      | 女   | 1999-09-23 00:00:00 | 一班   |
| 103     | 王尼玛    | 男   | 1988-01-11 00:00:00 | 一班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
+---------+-----------+------+---------------------+--------+
7 rows in set (0.25 sec)

25)

  • 查询存在85分以上成绩的课程号
mysql> select * from score;
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 100     | 3-245   |     85 |
| 101     | 3-245   |     95 |
| 102     | 3-105   |     83 |
| 103     | 3-105   |     89 |
| 104     | 3-245   |     66 |
| 105     | 6-166   |     60 |
| 106     | 6-166   |     92 |
+---------+---------+--------+
7 rows in set (0.05 sec)


mysql> select cnumber from score where degree >85;
+---------+
| cnumber |
+---------+
| 3-245   |
| 3-105   |
| 6-166   |
+---------+
3 rows in set (0.12 sec)

26)

  • 查询通信工程系教师所教课程的成绩表
mysql> select * from score where cnumber in (select cnumber from course where tnumber in (select tnumber from teacher where depart='通信工程系') );
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 100     | 3-245   |     85 |
| 101     | 3-245   |     95 |
| 104     | 3-245   |     66 |
+---------+---------+--------+
3 rows in set (0.00 sec)

27)

  • 查询计算机系 与化学系 不同职称的教师的tname和prof(职称)

==》第一步:查询计算机系与化学系中职称不相同的老师 ,用到not in,他们的职称在其他系没有出现过的老师

mysql> select * from teacher where depart='计算机系' 
       and prof not in(select prof from teacher where depart='通信工程系');
+---------+-------+------+---------------------+-----------+--------------+
| tnumber | tname | tsex | tbirthday           | prof      | depart       |
+---------+-------+------+---------------------+-----------+--------------+
| 112     | 王    | 男   | 2000-09-03 00:00:00 | 副教授    | 计算机系     |
+---------+-------+------+---------------------+-----------+--------------+
1 row in set (0.51 sec)

==》第二步:再反过来查通信工程系中与计算机系中不重复的

mysql> select * from teacher where depart='计算机系' 
       and prof not in(select prof from teacher where depart='通信工程系');
+---------+-------+------+---------------------+-----------+--------------+
| tnumber | tname | tsex | tbirthday           | prof      | depart       |
+---------+-------+------+---------------------+-----------+--------------+
| 112     | 王    | 男   | 2000-09-03 00:00:00 | 副教授    | 计算机系     |
+---------+-------+------+---------------------+-----------+--------------+
1 row in set (0.51 sec)

==》第三步:这两个语句可以通过union连接在一起,求并集

mysql> select * from teacher where depart='计算机系' and prof not in(select prof from teacher where depart='通信工程系')
   -> union   #连接在一起
   -> select * from teacher where depart='通信工程系' and prof not in(select prof from teacher where depart='计算机系');
+---------+--------+------+---------------------+-----------+-----------------+
| tnumber | tname  | tsex | tbirthday           | prof      | depart          |
+---------+--------+------+---------------------+-----------+-----------------+
| 112     | 王     | 男   | 2000-09-03 00:00:00 | 副教授    | 计算机系        |
| 113     | 春丽   | 女   | 1988-11-05 00:00:00 | 助教      | 通信工程系      |
| 114     | 刘邦   | 男   | 1978-12-03 00:00:00 | 助教      | 通信工程系      |
+---------+--------+------+---------------------+-----------+-----------------+
3 rows in set (0.38 sec)

28)

  • 查询编号为‘3-105’课程且成绩至少高于编号为‘3-245’的成绩,这些人的cnumber,snumber和degree,并且按照degree的大小进行由高到低的排序(any)
mysql> select * from score
    -> where cnumber='3-105' #条件一
    -> and degree>any(select degree from score where cnumber = '3-245')#条件二
    -> order by degree desc;  #排序
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 103     | 3-105   |     89 |
| 102     | 3-105   |     83 |
+---------+---------+--------+
2 rows in set (0.39 sec)

注意:至少 = any

29)

  • 查询编号为‘3-105’的课程且成绩高于课程‘3-245’课程的同学的信息?(all)
	mysql> select * from score
    -> where cnumber='3-105' #条件一
    -> and degree>all(select degree from score where cnumber = '3-245');

30)

  • 查询所有教师和同学的name、sex和birthday(union、as)
mysql> select tname,tsex,tbirthday from teacher
    -> union
    -> select sname,ssex,sbirthday from student;
+-----------+------+---------------------+
| tname     | tsex | tbirthday           |
+-----------+------+---------------------+
| 古一      | 女   | 0000-01-01 00:00:00 |
| 王        | 男   | 2000-09-03 00:00:00 |
| 春丽      | 女   | 1988-11-05 00:00:00 |
| 刘邦      | 男   | 1978-12-03 00:00:00 |
| 张三      | 男   | 1999-09-01 00:00:00 |
| 李四      | 男   | 1999-02-11 00:00:00 |
| 王二      | 女   | 1999-09-23 00:00:00 |
| 王尼玛    | 男   | 1988-01-11 00:00:00 |
| 张全蛋    | 男   | 2000-09-03 00:00:00 |
| 赵铁柱    | 男   | 1983-04-05 00:00:00 |
| 木子      | 女   | 2000-12-16 00:00:00 |
+-----------+------+---------------------+
11 rows in set (0.06 sec)

但是会发现,上面的字段不对是tname,这里就要取 别名 …as…

mysql> select tname as name,tsex as sex,tbirthday as birthday from teacher
    -> union
    -> select sname,ssex,sbirthday from student;
+-----------+-----+---------------------+
| name      | sex | birthday            |
+-----------+-----+---------------------+
| 古一      | 女  | 0000-01-01 00:00:00 |
| 王        | 男  | 2000-09-03 00:00:00 |
| 春丽      | 女  | 1988-11-05 00:00:00 |
| 刘邦      | 男  | 1978-12-03 00:00:00 |
| 张三      | 男  | 1999-09-01 00:00:00 |
| 李四      | 男  | 1999-02-11 00:00:00 |
| 王二      | 女  | 1999-09-23 00:00:00 |
| 王尼玛    | 男  | 1988-01-11 00:00:00 |
| 张全蛋    | 男  | 2000-09-03 00:00:00 |
| 赵铁柱    | 男  | 1983-04-05 00:00:00 |
| 木子      | 女  | 2000-12-16 00:00:00 |
+-----------+-----+---------------------+
11 rows in set (0.00 sec)

注意:第二排可以不用取别名,默认按第一排取别名

31)

  • 查询所有女教师和女同学的name、sex和birthday

==》在两个查询语句后面加上where条件就可以,在用union连接where tsex='女'+where ssex=‘女’

32)

  • 查询成绩比课程平均成绩低的同学的成绩表

==》第一步:先查一下各门课的平均成绩

mysql> select avg(degree) from score group by cnumber;
+-------------+
| avg(degree) |
+-------------+
|     86.0000 |
|     82.0000 |
|     76.0000 |
+-------------+
3 rows in set (0.56 sec)

==》第二步:求某一门课的平均成绩

mysql> select avg(degree) from score where cnumber='3-105';
+-------------+
| avg(degree) |
+-------------+
|     86.0000 |
+-------------+
1 row in set (0.00 sec)

==》第三步:把score复制成a、b两个表(不需要语句,直接写)

mysql> select * from score a where
    -> degree<(select avg(degree) from score b where a.cnumber=b.cnumber);
+---------+---------+--------+
| snumber | cnumber | degree |
+---------+---------+--------+
| 102     | 3-105   |     83 |
| 104     | 3-245   |     66 |
| 105     | 6-166   |     60 |
+---------+---------+--------+
3 rows in set (0.40 sec)

33)

  • 查询所有任课老师的tname和depart
mysql> select tname,depart from teacher
    -> where tnumber in (select tnumber from course);
+--------+-----------------+
| tname  | depart          |
+--------+-----------------+
| 古一   | 化学系          |
| 王     | 计算机系        |
| 春丽   | 通信工程系      |
| 刘邦   | 通信工程系      |
+--------+-----------------+
4 rows in set (0.57 sec)

分析:这一题乍一看很简单,其实有点小条件,就是任课老师的名字。因为老师表里面可能有不任课的老师,所以要和course表进行比较,找到teccher表中教师号在课程表中存在的任课老师

34)

  • 查询至少有2个男生的班号

==》第一步:查看学生表

mysql> select * from student;
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 102     | 王二      | 女   | 1999-09-23 00:00:00 | 一班   |
| 103     | 王尼玛    | 男   | 1988-01-11 00:00:00 | 一班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
+---------+-----------+------+---------------------+--------+
7 rows in set (0.00 sec)

==》第二步:count(*)统计男生的个数

mysql> select class from student 
       where ssex='男' group by class having count(*)>=2;
+--------+
| class  |
+--------+
| 一班   |
+--------+
1 row in set (0.00 sec)

35)

  • 查询student表中不姓 ‘王’ 的同学记录
  • 用法:not like(模糊查询)
mysql> select * from student where sname not like '王%';
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
+---------+-----------+------+---------------------+--------+
5 rows in set (0.37 sec)

36)

  • 查询student表中每个学生的姓名和年龄
mysql> select sname,year(now())-year(sbirthday) as old from student;
+-----------+------+
| sname     | old  |
+-----------+------+
| 张三      |   20 |
| 李四      |   20 |
| 王二      |   20 |
| 王尼玛    |   31 |
| 张全蛋    |   19 |
| 赵铁柱    |   36 |
| 木子      |   19 |
+-----------+------+
7 rows in set (0.00 sec)

分析:年龄=当前年份 - 出生年份,当前年份可以用 year( now())来体现,再加上别名

37)

  • 查询student表中最大最小sbirthday的日期值
mysql> select sbirthday from student order by sbirthday;
+---------------------+
| sbirthday           |
+---------------------+
| 1983-04-05 00:00:00 |
| 1988-01-11 00:00:00 |
| 1999-02-11 00:00:00 |
| 1999-09-01 00:00:00 |
| 1999-09-23 00:00:00 |
| 2000-09-03 00:00:00 |
| 2000-12-16 00:00:00 |
+---------------------+
7 rows in set (0.01 sec)

这里可以使用max()、min()函数

mysql> select max(sbirthday) as max,min(sbirthday) as min
       from student order by sbirthday;
+---------------------+---------------------+
| max                 | min                 |
+---------------------+---------------------+
| 2000-12-16 00:00:00 | 1983-04-05 00:00:00 |
+---------------------+---------------------+
1 row in set (0.00 sec)

38)

  • 以班级和年龄从大到小的顺序查询student表中的记录
mysql> select * from student order by class desc,sbirthday;
+---------+-----------+------+---------------------+--------+
| snumber | sname     | ssex | sbirthday           | class  |
+---------+-----------+------+---------------------+--------+
| 105     | 赵铁柱    | 男   | 1983-04-05 00:00:00 | 二班   |
| 106     | 木子      | 女   | 2000-12-16 00:00:00 | 二班   |
| 103     | 王尼玛    | 男   | 1988-01-11 00:00:00 | 一班   |
| 101     | 李四      | 男   | 1999-02-11 00:00:00 | 一班   |
| 100     | 张三      | 男   | 1999-09-01 00:00:00 | 一班   |
| 102     | 王二      | 女   | 1999-09-23 00:00:00 | 一班   |
| 104     | 张全蛋    | 男   | 2000-09-03 00:00:00 | 一班   |
+---------+-----------+------+---------------------+--------+
7 rows in set (0.00 sec)

分析:这里的年龄要从大到小,因为年份排序是根据年的大小来排序的(2000年>1988年),所以不需要指定降序,默认的升序对年龄来说就是从大到小。

注意:这里order by是先按照第一进行排列,第一个相同再按照第二个进行排列

39)

  • 查询男教师以及所上的课程
mysql> select * from teacher where tsex='男';
+---------+--------+------+---------------------+-----------+-----------------+
| tnumber | tname  | tsex | tbirthday           | prof      | depart          |
+---------+--------+------+---------------------+-----------+-----------------+
| 112     | 王     | 男   | 2000-09-03 00:00:00 | 副教授    | 计算机系        |
| 114     | 刘邦   | 男   | 1978-12-03 00:00:00 | 助教      | 通信工程系      |
+---------+--------+------+---------------------+-----------+-----------------+
2 rows in set (0.00 sec)

mysql> select * from course 
       where tnumber in ( select tnumber from teacher where tsex='男');
+---------+--------------+---------+
| cnumber | cname        | tnumber |
+---------+--------------+---------+
| 3-105   | 数据结构     | 112     |
| 9-888   | 数字电路     | 114     |
+---------+--------------+---------+
2 rows in set (0.00 sec)

分析:可以先查男教师,然后再作为条件来用

40)

  • 查询最高分同学的信息
mysql> select * from student where
    -> snumber=(select snumber from score where
       degree=( select max(degree) from score) );
+---------+--------+------+---------------------+--------+
| snumber | sname  | ssex | sbirthday           | class  |
+---------+--------+------+---------------------+--------+
| 101     | 李四   | 男   | 1999-02-11 00:00:00 | 一班   |
+---------+--------+------+---------------------+--------+
1 row in set (0.00 sec)

分析:由最高分找学号,再由学号找信息

41)

  • 查询和王尼玛同性别的同学名字
mysql> select sname from student 
       where ssex=(select ssex from student where sname='王尼玛');
+-----------+
| sname     |
+-----------+
| 张三      |
| 李四      |
| 王尼玛    |
| 张全蛋    |
| 赵铁柱    |
+-----------+
5 rows in set (0.00 sec)

42)

  • 查询和王尼玛同性别且同班的同学名字
mysql> select sname from student 
       where ssex=(select ssex from student where sname='王尼玛')    
    -> and class=(select class from student where sname='王尼玛');
+-----------+
| sname     |
+-----------+
| 张三      |
| 李四      |
| 王尼玛    |
| 张全蛋    |
+-----------+
4 rows in set (0.00 sec)

43)

  • 查询所有选修‘人工智能’课程的男同学的成绩

步骤:

  • 先从mysql> select cnumber from course where cname='人工智能';找到cnumber
  • 再从mysql> select snumber from student where ssex='男';找到snumber
  • 然后进行子查询:
mysql> select degree from score
    -> where cnumber=(select cnumber from course where cname='人工智能')
    -> and snumber in (select snumber from student where ssex='男');
+--------+
| degree |
+--------+
|     60 |
+--------+
1 row in set (0.00 sec)

注意:这里snumber有多个要用 in ,只有一个用 =

44)

  • 使用如下命令建立一个grade表

==》第一步:建立一个等级表

mysql> create table grade(
    -> low int(3),
    -> upp int(3),
    -> grade char(1)
    -> );
Query OK, 0 rows affected (1.58 sec)

 insert into grade values(90,100,'A');
 insert into grade values(80,89,'B');
 insert into grade values(70,79,'C');
 insert into grade values(60,69,'D');
 insert into grade values(0,59,'E');
 
 mysql> select * from grade;
+------+------+-------+
| low  | upp  | grade |
+------+------+-------+
|   90 |  100 | A     |
|   80 |   89 | B     |
|   70 |   79 | C     |
|   60 |   69 | D     |
|    0 |   59 | E     |
+------+------+-------+
5 rows in set (0.00 sec)

==》第二步:查询所有同学的snumber、cnumber、和grade列

mysql> select snumber,cnumber,grade from score,grade
    -> where degree between low and upp order by grade;  #再排个序
+---------+---------+-------+
| snumber | cnumber | grade |
+---------+---------+-------+
| 106     | 6-166   | A     |
| 101     | 3-245   | A     |
| 100     | 3-245   | B     |
| 102     | 3-105   | B     |
| 103     | 3-105   | B     |
| 105     | 6-166   | D     |
| 104     | 3-245   | D     |
+---------+---------+-------+
7 rows in set (0.00 sec)
原文地址:https://www.cnblogs.com/fxyadela/p/11604688.html