【MySQL】主键、唯一键和外键
主键
作用:
在一个table中,标识一行记录的唯一性。
语法:
create table时,可以紧随列属性声明的后面,如id int primary key
,也可以单独成一行,如下:
mysql> show create table student \G
*************************** 1. row ***************************
Table: student
Create Table: CREATE TABLE `student` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`gender` enum('男','女') DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
-
表已存在,添加主键
alter table 表名 add primary key (已存在的字段列表);
-
删除主键
alter table 表名 drop primary key;
复合主键:
mysql> show create table t3 \G
*************************** 1. row ***************************
Table: t3
Create Table: CREATE TABLE `t3` (
`course` varchar(20) NOT NULL,
`name` varchar(20) NOT NULL,
`gender` enum('男','女') DEFAULT NULL,
PRIMARY KEY (`course`,`name`) #括号里面以逗号区分复合主键的每一个成分
) ENGINE=InnoDB DEFAULT CHARSET=utf8
多个属性组合为一个整体,以标识数据记录的唯一性,就是复合主键。要将复合主键看作一个整体,即复合主键也只是一个主键,只不过包含了多个属性。
唯一键
作用:
保证同一张table内,多条数据的某个字段的唯一性。
语法(和定义主键的语法差不多):
mysql> show create table student \G
*************************** 1. row ***************************
Table: student
Create Table: CREATE TABLE `student` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`gender` enum('男','女') DEFAULT NULL,
`telephone` char(11) DEFAULT NULL,
`wechat` varchar(15) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `telephone` (`telephone`),
UNIQUE KEY `wechat` (`wechat`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
-
添加唯一键
alter table 表名 add unique key (已存在的字段列表);
复合唯一键:
道理和复合主键类似,也支持整合多个字段为一个唯一键(如下,创建一个学生信息表,以’班级-班内编号’作为一个复合唯一键)
mysql> show create table t4 \G
*************************** 1. row ***************************
Table: t4
Create Table: CREATE TABLE `t4` (
`id` int(3) unsigned zerofill NOT NULL,
`name` varchar(20) NOT NULL,
`class` char(10) DEFAULT NULL,
`classid` tinyint(3) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `in_class` (`class`,`classid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> select * from t4;
+-----+--------+------------+---------+
| id | name | class | classid |
+-----+--------+------------+---------+
| 001 | 张三 | 2021200101 | 1 |
| 002 | 李四 | 2021200103 | 1 |
| 008 | 老刘 | 2021200103 | 2 |
+-----+--------+------------+---------+
每个学生的class可以相同,classid可以相同,但是class-classid组合起来就必须是唯一的。
The difference between primary key and unique key:
- 主键不允许为NULL,唯一键允许为NULL
- 一个table中,主键只能有一个(包括复合主键),唯一键可以有多个
- 主键侧重于标识一条记录(一行)的唯一性;而唯一键侧重于保证在业务上,某个属性在多个记录中的唯一
tips
- 主键和唯一键一般在字段插入具体数据之前指定(最好是建表时指定),否则可能会发生已经存在重复数据,再指定key。
- 主键和唯一键都有复合的形式,这在业务逻辑中很常见,比如,某个班的某个同学,他的‘班级号-班内编号’组合一定是唯一的。
- 一般而言,我们建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对主键做过大的调整 。
- 删除主键和唯一键的动作很危险,要谨慎。
外键
作用:
在表与表之间建立联系,使彼此的增删查改操作受到另一方一定的影响。在foreign key的语境中,会有一张主表和一张从表,外键约束主要定义在从表上,主表则必须是有主键约束或唯一键约束,从表可以引用主表的primary key或unique key作为自己的外键,以此建立与主表的联系。
Demo场景:学生与班级的关系,学生一定从属于某个存在的班级。
从表指定外键的语法
foreign key (字段名) references 主表名(字段名)
建立主表class
mysql> show create table class \G
*************************** 1. row ***************************
Table: class
Create Table: CREATE TABLE `class` (
`id` tinyint(3) unsigned zerofill NOT NULL,
`type` enum('实验班','普通班') DEFAULT '普通班',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
mysql> desc class;
+-------+-------------------------------+------+-----+-----------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------------------------+------+-----+-----------+-------+
| id | tinyint(3) unsigned zerofill | NO | PRI | NULL | |
| type | enum('实验班','普通班') | YES | | 普通班 | |
+-------+-------------------------------+------+-----+-----------+-------+
建立从表student
mysql> show create table student \G
*************************** 1. row ***************************
Table: student
Create Table: CREATE TABLE `student` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`gender` enum('男','女') DEFAULT NULL,
`telephone` char(11) DEFAULT NULL,
`wechat` varchar(15) DEFAULT NULL,
`class_id` tinyint(3) unsigned zerofill DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `telephone` (`telephone`),
UNIQUE KEY `wechat` (`wechat`),
KEY `class_id` (`class_id`),
CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`) #重点在这里
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> desc student;
+-----------+------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| gender | enum('男','女') | YES | | NULL | |
| telephone | char(11) | YES | UNI | NULL | |
| wechat | varchar(15) | YES | UNI | NULL | |
| class_id | tinyint(3) unsigned zerofill | YES | MUL | NULL | |
+-----------+------------------------------+------+-----+---------+----------------+
实际场景中,学生的信息在student表中存储,由于学生必然从属于某个班级,因此还需要存储学生班级的信息,由于多个学生可能共属于同一个班级,如果直接在student表中增加班级属性的列(如班级编号、班级类型等),会使student表的数据冗余。因此可以用另一个表class存储班级信息,再将class表作为主表,student表作为从表,建立外键联系。student表的class_id
指的是学生的班级id,而这个class_id
与class表的字段id
建立了外键联系,这样在student表中,每个学生只需要存储一个class_id,就可以到class表中找到对应的班级信息,减少数据冗余。
试着向两个表插入一些数据!
mysql> select * from class;
+-----+-----------+
| id | type |
+-----+-----------+
| 001 | 普通班 |
| 002 | 实验班 |
+-----+-----------+
2 rows in set (0.00 sec)
mysql> select * from student;
+----+--------+--------+-------------+--------+----------+
| id | name | gender | telephone | wechat | class_id |
+----+--------+--------+-------------+--------+----------+
| 1 | 张伟 | 男 | 12345678910 | 5555 | 001 |
| 2 | 一菲 | 女 | 11233113344 | 6666 | 002 |
+----+--------+--------+-------------+--------+----------+
6 rows in set (0.00 sec)
如果向student表中插入在class表中不存在的class_id,MySQL会拦截
mysql> insert into student (name, gender, telephone, wechat, class_id) values ('小贤','男',11111111222,7777, 3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ckf_d3`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
如果从class表中删除了在student中已经存在的class_id,MySQL也不允许这样做
mysql> delete from class where id=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`ckf_d3`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
建立外键约束的本质其实就是把表与表之间逻辑上的相关性交给mysql去审核了,提前告诉mysql表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!