【MySQL】主键、唯一键和外键

发布时间:2023年12月17日

文章目录


主键

作用:

在一个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:

  1. 主键不允许为NULL,唯一键允许为NULL
  2. 一个table中,主键只能有一个(包括复合主键),唯一键可以有多个
  3. 主键侧重于标识一条记录(一行)的唯一性;而唯一键侧重于保证在业务上,某个属性在多个记录中的唯一

tips

  1. 主键和唯一键一般在字段插入具体数据之前指定(最好是建表时指定),否则可能会发生已经存在重复数据,再指定key。
  2. 主键和唯一键都有复合的形式,这在业务逻辑中很常见,比如,某个班的某个同学,他的‘班级号-班内编号’组合一定是唯一的。
  3. 一般而言,我们建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对主键做过大的调整 。
  4. 删除主键和唯一键的动作很危险,要谨慎。

外键

作用:

在表与表之间建立联系,使彼此的增删查改操作受到另一方一定的影响。在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不允许你插入!

文章来源:https://blog.csdn.net/C0631xjn_/article/details/135001617
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。