存储关系
现在有学生表、科目表这两张表,我需要再创建一张成绩表,用来表示学生各科目的成绩,
如下 :
一个学生可以有多个成绩,一个成绩只能属于某个学生,一个 科目 可以有多个成绩,一个成绩只能属于某个科目。
把外键 存到 1 对 n 中的 n 里面去。
即 : 一对多的情况下,在 多 的那张表里面创建一个外键指向 一 的那张表 的 id,
多对多的 情况下需要创建第三张表用来存储这两种表的id作为外键以及这两张表的关系,就比如这里的 学生 与 成绩。
如下创建成绩表。
create table scores(id int auto_increment primary key,
stuid int,
subid int,
score decimal(5,2),
foreign key(stuid) references students(id),
foreign key(subid) references subjects(id));
比如我需要插入一条数据,学号 为 1 的 学生 的 id 为1的科目 考了 100分
insert into scores value(0,1,1,100);
外键的级联操作
在删除 student表的数据时,如果这个 id 值在 scores 中已经存在,则会抛出异常
推荐使用逻辑删除,还可以解决这个问题
可以创建表时指定级联操作,也可以在创建表后再修改外键的级联操作
语法 :
alert table scores add constraint stu_sco foreign key(stuid) references student;
级联操作的类型包括 :
restrict(限制) : 默认值,抛出异常
cascade(级联) : 如果主表 的记录被删除,则从表中相关联的记录都会被删掉
set null : 将外键设置为空
no action : 什么都不做
连接查询
比如我现在要看所有学生的成绩,需要显示
名字 科目 成绩
students.name subjecys.stitle scores.score
而我只查成绩表给出的是 id ,而 id 对应的表在另外一张表里面,这样就需要进行连接查询。
如下 :
select students.name,subjects.stitle,scores.score
from scores
inner join students on scores.stuid=students.id
inner join subjects on scores.subid=subjects.id;
或者 :
select students.name,subjects.stitle,scores.score
from students
inner join scores on scores.stuid=students.id
inner join subjects on scores.subid=subjects.id;
结果 :
+--------+--------+-------+
| name | stitle | score |
+--------+--------+-------+
| 郭靖 | python | 99.00 |
+--------+--------+-------+
1 row in set (0.00 sec)
1.当你的结果集来源于多张表的时候就要考虑连接查询 。
2.先找到这些表的关系 ,如例 : 科目 和学生没有直接关系,学生 和成绩有直接 关系,科目和成绩也有直接 关系,由此所有 的 关系都建立起来 了。
3.构造 sql 语句, 注意语法的 join 和 on 关键字 。
语法 :
select 表名1.字段1 , 表名2.字段3 ,表名2.字段3,..
from 表名1(作为基础的表)
inner join 表名2 on 表名1.外键2=表名2.id
inner join 表名3 on 表名1.外键3=表名3.id;
其中 from 随便先写 哪张表无所谓,但是 on 后面的条件一定不能错。
join 左边的表 称为 左表, join 右边的表 称为 右表 。
还有一点 要注意 , to 后面的表,一定要先在 to 前面出现过,否则会报错,如下
select students.name,subjects.stitle,scores.score
from students
inner join subjects on scores.stuid=students.id
inner join scores on scores.subid=subjects.id;
ERROR 1054 (42S22): Unknown column 'scores.stuid' in 'on clause'
连接查询分为三种 :
一、表A inner join 表B (内连接): 表A与表B匹配的行会出现在结果集中。
二、表A left join 表B (左连接):表A与表B匹配的行会出现在结果集中,外加表A中独有的数据,
未对应的数据使用 null 填充。
select * from scores right join students on scores.stuid=students.id;
+------+-------+-------+-------+----+-----------+--------+---------------------+----------+-----------+
| id | stuid | subid | score | id | name | gender | brithday | isDelete | hometwon |
+------+-------+-------+-------+----+-----------+--------+---------------------+----------+-----------+
| 6 | 7 | 1 | 99.00 | 7 | 郭靖 | | 0000-00-00 00:00:00 | | 蒙古 |
| 7 | 7 | 10 | 99.00 | 7 | 郭靖 | | 0000-00-00 00:00:00 | | 蒙古 |
| NULL | NULL | NULL | NULL | 2 | 黄蓉 | | 1994-02-14 00:00:00 | | 桃花岛 |
| NULL | NULL | NULL | NULL | 3 | 杨过 | | 1994-02-14 00:00:00 | | NULL |
| NULL | NULL | NULL | NULL | 4 | 小龙女 | | 1994-02-14 00:00:00 | | NULL |
| NULL | NULL | NULL | NULL | 5 | 雕 | | 1994-02-14 00:00:00 | | NULL |
+------+-------+-------+-------+----+-----------+--------+---------------------+----------+-----------+
6 rows in set (0.00 sec)
select * from scores left join students on scores.stuid=students.id;
+----+-------+-------+-------+------+--------+--------+---------------------+----------+----------+
| id | stuid | subid | score | id | name | gender | brithday | isDelete | hometwon |
+----+-------+-------+-------+------+--------+--------+---------------------+----------+----------+
| 6 | 7 | 1 | 99.00 | 7 | 郭靖 | | 0000-00-00 00:00:00 | | 蒙古 |
| 7 | 7 | 10 | 99.00 | 7 | 郭靖 | | 0000-00-00 00:00:00 | | 蒙古 |
+----+-------+-------+-------+------+--------+--------+---------------------+----------+----------+
2 rows in set (0.00 sec)
左连接时数据的条数 以 join 左边的表为准,字段则是左边的表和右边的表合起来的字段拼接而成。
而左表中某些数据在右表中没有出现则用 null 对应, 这样结果集就是 由这两张表合成 的表。
三、表A right join 表B (右连接):表A与表B匹配的行会出现在结果集中,外加表B中独有的数据,未对应的数据使用 null 填充。
右连接跟左连接相反
查询每个学生的平均成绩 :
select name,avg(score) from scores inner join students on scores.stuid=students.id group by stuid;
+--------+------------+
| name | avg(score) |
+--------+------------+
| 郭靖 | 99.000000 |
+--------+------------+
1 row in set (0.03 sec)
而
select * from scores inner join students on scores.stuid=students.id group by stuid;
+----+-------+-------+-------+----+--------+--------+---------------------+----------+----------+
| id | stuid | subid | score | id | name | gender | brithday | isDelete | hometwon |
+----+-------+-------+-------+----+--------+--------+---------------------+----------+----------+
| 6 | 7 | 1 | 99.00 | 7 | 郭靖 | | 0000-00-00 00:00:00 | | 蒙古 |
+----+-------+-------+-------+----+--------+--------+---------------------+----------+----------+
1 row in set (0.00 sec
思路 : 先通过连接查询得到一张大表,里面包含有成绩的学生的学生信息 和成绩信息,
再在这个结果集里面筛选需要的字段 。
select distinct 列/*
from 表1 inner/left/right join 表2 on 表1与表2的关系
where ...
group by ... having ...
order by ... asc/desc
limit sart,count;