mysql 外键

一、概念

mysql多表指的是多张表之间建立联系。其中有一下几种关系

1.一对一

一张表中的一条记录与另外一张表中有且仅有一条记录有关系

2.一对多

一对多也叫做多对一,含义就是:一张表中的一条记录与另外一张表中的多条记录对应,反过来另外一张表中的多条记录只能对应当前表中的一条记录
一对多的关系在实际生产当中使用非常常见。
一对多的核心解决方案是:如何让记录能够正确的匹配到另外表中的数据

3.对多多

多对多关系在生产中也比较常见
多对多关系是无法在自身表中维护对应表关系的,需要通过第三方表来实现将多对多关系变成多对一的关系
也就是说设计一个中间表:记录两表之间的对应关系
中间表与其他表都是多对一的关系

二、外键约束

1.外键

“foreign key”,在一张表中指向外部表 “主键” 的字段定义成为 “外键”

1.1 语法

外键必须要通过语法指定才能称之为外键.
外键也可以不指定名称,系统会自动生成

[constraint 外键名] foreign key(当前表字段名) references 外部表(主键字段)
1.2 外键构成条件

​ 外键字段必须与对应表的主键字段类型一致
​ 外键字段本身要求是一个索引(创建外键会自动生成一个索引)

1.3 实例
创建班级表
create table class( 
    id int primary key auto_increment, 
    name varchar(50) not null unique 
)charset utf8;

创建学生表
create table students( 
    id int primary key auto_increment,
    name varchar(50) not null,c_id int comment  "指向class表的主键",
    foreign key(c_id) references class(id)
);

查看两张表

mysql> desc class;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(50) | NO   | UNI | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)


mysql> desc students;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(50) | NO   |     | NULL    |                |
| c_id  | int(11)     | YES  | MUL | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)


#发现c_id 字段变成了索引
mysql> show create table students\G
*************************** 1. row ***************************
       Table: students
Create Table: CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `c_id` int(11) DEFAULT NULL COMMENT '指向class表的主键',
  PRIMARY KEY (`id`),
  KEY `c_id` (`c_id`),
  CONSTRAINT `students_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`)   #这里mysql自动创建了外键名字,叫做students_ibfk_1
) ENGINE=InnoDB DEFAULT CHARSET=latin1




2.外键约束

当表建立外键之后,外键就会对主表(外键指向的表)和子表(外键所在的表)里的数据产生约束效果。
外键约束的是写操作(默认操作)

2.1 新增

子表插入的数据对应的外键必须在主表存在

mysql> select * from class;
Empty set (0.00 sec)

mysql> select * from students;
Empty set (0.00 sec

#插入数据失败
mysql> insert into students values(NULL,"zhangsan",1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`huabeidb`.`students`, CONSTRAINT `students_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`))

2.2 修改

主表的记录如果在子表存在,那么主表的主键不能修改(注意是主键字段,别的字段可以修改)

mysql> insert into class values(NULL,"python");
Query OK, 1 row affected (0.01 sec)

mysql> select * from class;
+----+--------+
| id | name   |
+----+--------+
|  1 | python |
+----+--------+
1 row in set (0.00 sec)

mysql> insert into students values(NULL,"zhangsan",1);
Query OK, 1 row affected (0.01 sec)

mysql> select * from students;
+----+----------+------+
| id | name     | c_id |
+----+----------+------+
|  2 | zhangsan |    1 |
+----+----------+------+
1 row in set (0.00 sec)

# 此时students 中的zhangsan 已经和 class表的 python记录做了对应

#更改class表的主键ID失败
mysql> update class set id = 10 where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`huabeidb`.`students`, CONSTRAINT `students_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`))
2.3 删除

主表的记录如果在子表存在,那么主表的主键不能删除

mysql> delete from  class where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`huabeidb`.`students`, CONSTRAINT `students_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`))

3.外键约束控制

外键可以在定义时控制外键的约束作用

3.1 控制类型
on update: 父表更新时子表的表现
on delete: 父表删除时子表的表现
3.2 控制方式
cascade: 级联操作,父表操作后子表跟随操作
set null: 置空操作,父表操作后,子表关联的外键字段置空
restrict: 严格模式,不允许父表操作(默认)
no action:子表没有动作


3.3 外键约束控制原则
更新级联: on update cascade
删除置空: on delete set null

4.外键管理

4.1 新增外键
alter table 表名 add [constraint `外键名`] foreign key(外键字段) references 主表名(主键) [ on 外键约束]
4.2 删除外键
alter table 表名 drop foreign key 外键名;
4.3 更新外键

先删除后新增

#查看表的外键名称
mysql> show create table students\G
*************************** 1. row ***************************
       Table: students
Create Table: CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `c_id` int(11) DEFAULT NULL COMMENT '指向class表的主键',
  PRIMARY KEY (`id`),
  KEY `c_id` (`c_id`),
  CONSTRAINT `students_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

#删除外键
mysql> alter table students drop foreign key students_ibfk_1;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0


#在次查看 外键已经没有了
mysql> show create table students\G
*************************** 1. row ***************************
       Table: students
Create Table: CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `c_id` int(11) DEFAULT NULL COMMENT '指向class表的主键',
  PRIMARY KEY (`id`),
  KEY `c_id` (`c_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)


#新增外键 并加上约束控制
mysql> alter table students add foreign key students(c_id) references class(id) on update cascade on delete set null;
Query OK, 1 row affected (0.03 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> show create table students\G
*************************** 1. row ***************************
       Table: students
Create Table: CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `c_id` int(11) DEFAULT NULL COMMENT '指向class表的主键',
  PRIMARY KEY (`id`),
  KEY `students` (`c_id`),
  CONSTRAINT `students_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
修改验证
mysql> select * from class;
+----+--------+
| id | name   |
+----+--------+
|  1 | python |
+----+--------+
1 row in set (0.00 sec)

mysql> select * from students;
+----+----------+------+
| id | name     | c_id |
+----+----------+------+
|  2 | zhangsan |    1 |
+----+----------+------+
1 row in set (0.00 sec)


修改class表主键

mysql> update class set id = 10 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from class;
+----+--------+
| id | name   |
+----+--------+
| 10 | python |
+----+--------+

查看students表的变化,发现也跟着变化了。

mysql> select * from students;
+----+----------+------+
| id | name     | c_id |
+----+----------+------+
|  2 | zhangsan |   10 |
+----+----------+------+
1 row in set (0.00 sec)
删除验证
mysql> select * from students;
+----+----------+------+
| id | name     | c_id |
+----+----------+------+
|  2 | zhangsan |   10 |
+----+----------+------+
1 row in set (0.00 sec)

mysql> delete from class where id = 10;
Query OK, 1 row affected (0.00 sec)

mysql> select * from students;
+----+----------+------+
| id | name     | c_id |
+----+----------+------+
|  2 | zhangsan | NULL |
+----+----------+------+
1 row in set (0.00 sec)

5.外键的创建时机

外键的使用最好在创建表结构的时候就维护好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值