MySQL 学习笔记(二)
(2019.7.24)
今天开了一个新的笔记,便于查看啦~ ~ ~开始喽
一、数据库的 三大设计范式
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)
创建了三个表,下面我经历了很长时间的数据输入(心累…)直接看成果吧
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)
今天就到这里了,去睡觉啦,一点啦~
2、查询练习
(2019.7.26)
上面我们已经创建好了数据,下面开始查询练习:
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列
如果我们这样去查询depatt列
mysql> select depart from teacher;
+-----------------+
| depart |
+-----------------+
| 化学系 |
| 计算机系 |
| 通信工程系 |
| 通信工程系 |
+-----------------+
4 rows in set (0.00 sec)
发现查询的结果有重复的,可以在select后面加一个distinct(排除重复)
结果就没有重复的单位了
mysql> select distinct depart from teacher;
mysql> select distinct depart from teacher;
+-----------------+
| depart |
+-----------------+
| 化学系 |
| 计算机系 |
| 通信工程系 |
+-----------------+
3 rows in set (0.10 sec)
4、查询score表中成绩 60到90 之间的所有记录
这就要给我们查询指令加一个查询区间:( between 。。 and 。。)
mysql> select * from score where degree between 60 and 80;
也可以直接使用运算符比较:
mysql> select * from score where degree >= 60 and degree<= 90;
两条指令结果是一样的(注意between包括端点值)
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表中的记录
升序asc、降序desc
mysql> select * from student order by snumber(什么字段) desc(降序);
数据库默认排序方式是升序排列的,不输入asc结果相同:
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;
这条语句会先按照教师号升序排列,遇到相同的教师号再按照成绩降序进行排列
(order by 先按照第一个排,再考虑第二个排列)
当两个同时排序的话,asc(升序)必须要写(sql8.0不写也没事)
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)
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);
排序的做法:
mysql> select snumber,cnumber,degree from score order by degree desc limit 0,1;
这里的 limit 0,1 表示取表中从第0条取到第一条(也就是取出第一条数据)
limit 的第一个数字表示从哪里开始查,第二个数字表示查几条
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)
11、查询每门课的平均成绩
通过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)
12、查询score表中至少有 两名学生选修 并以 3开头 的课程平均成绩(分组条件与模糊查询)
这个题看着有点难,我们先看一下score表,再分一下组
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.01 sec)
mysql> select cnumber from score group by cnumber;
+---------+
| cnumber |
+---------+
| 3-105 |
| 3-245 |
| 6-166 |
+---------+
3 rows in set (0.10 sec)
这时候给分组加上条件 having + 条件,就是分组后跟条件要使用having
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 ):
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)
OK~就学到这了,后面关于查询的联系还有不少,抽时间给它学了,还真得慢慢磨磨
(2019.7.27)
13、查询成绩大于70,小于90的列
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)
当然也可以写成这样
mysql> select snumber,degree from score
-> where degree between 70 and 90;
这两种方法可以相互替换实现范围查询,但是要注意between是包含端点的…
14、查询所有学生的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)
15、查询所有学生的snumber、cname、degree(多表查询)
这些信息来自于course表和score表,我们先查询一下这两个表中的内容,看一下有什么异样的数据,以便写限制条件
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)
也就是我们要查找共同写条件,让查询进行匹配~
16、查询所有学生的cname、sname,degree(三表关联查询)
找两两之间的相同之处,写条件
这里的 sname来自student表、cname来自course表,degree来自score表,也就是我们要查询的三个字段来自三张表
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
可以给要显示的列进行更名,但是仅仅局限于此次查询。通过结果可发现结果是相同的
(20197.28)
17、查询一班学生每门课的平均成绩
这里用到前面说的 in表示或者条件
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)
18、查询选修‘3-105’课程中成绩高于102号同学成绩的同学记录
(子查询)
这道题读题句很困难,我们一步一步做:
a、先把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)
b、有了这个条件,我们再加一个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)
这样就解决了~
19、查询所有课程的成绩高于‘3-105’课程中成绩高于102号同学成绩的同学记录
这题把~和上面那一题几乎类似,只是条件不同而已,把从3-105课程中查询大于102号同学成绩,放大到从整个表中查询比 102号同学的3-105课程成绩多的同学记录!
我们只要把上题的条件删除一个就好:
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)
20、查询学号为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)
这就找到了,这里用到了内置函数year()求年份
已经知道的函数 avg()求平均值,count()求和
21、查询‘古一’老师任课的学生成绩(多层嵌套子查询)
我们先看一下古一的个人信息:
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)
多层嵌套的子查询,查询结果作为另一个的条件
22、查询选修某门课人数多于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)
23、查询一班二班全体学生记录
这一看,肯定用 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)
24 、查询存在85分以上成绩的课程号
很简单这个,因为要查的数据都在一个表里(score)
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)
25、查询通信工程系教师所教课程的成绩表
这个依然是条件嵌套,就不多重复了
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)
26、查询 计算机系 与 化学系 不同职称的教师的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 |
+---------+--------+------+---------------------+--------+-----------------+
| 113 | 春丽 | 女 | 1988-11-05 00:00:00 | 助教 | 通信工程系 |
| 114 | 刘邦 | 男 | 1978-12-03 00:00:00 | 助教 | 通信工程系 |
+---------+--------+------+---------------------+--------+-----------------+
2 rows in set (0.00 sec)
这两个语句可以通过union连接在一起,求并集~
语句1 union 语句2;
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)
哎哎,这个查询的练习是真的多啊,这个暑假要把数据库过一遍,今天先这样了,下次新开一个吧。