十四MySQL 约束详解
Posted Amo Xiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十四MySQL 约束详解相关的知识,希望对你有一定的参考价值。
文章目录
前置知识:
一、数据库开发与实战专栏导学及数据库基础概念入门
二、MySQL 介绍及 MySQL 安装与配置
三、MySQL 数据库的基本操作
四、MySQL 存储引擎及数据类型
五、数据导入与基本的 SELECT 语句
六、MySQL 数据库练习题1(包含前5章练习题目及答案)
七、MySQL 多表查询详解(附练习题及答案----超详细)
八、MySQL 常用函数汇总(1)
九、MySQL 常用函数汇总(2)
十、MySQL 聚合函数、分组查询及过滤分组
十一、子查询详解
十二、创建和管理表
十三、表数据的增、删、改操作
数据完整性是指数据的正确性和相容性,是为了防止数据库中存在不符合语义的数据,即防止数据库中存在不正确的数据。在 mysql
中提供了多种完整性约束,它们作为数据库关系模式定义的一部分,可以通过 CREATE TABLE
或 ALTER TABLE
语句来定义。一旦定义了完整性约束,MySQL
服务器会随时检测处于更新状态的数据库内容是否符合相关的完整性约束,从而保证数据的一致性与正确性。这样,既能有效地防止对数据库的意外破坏,又能提高完整性检测的效率,还能减轻数据库编程人员的工作负担。本文将对数据完整性约束进行详细介绍。本章知识架构及重难点如下:
一、定义完整性约束
关系模型的完整性规则是对关系的某种约束条件。在关系模型中,提供了实体完整性、参照完整性和用户定义完整性3项规则。下面将分别介绍 MySQL
中对数据库完整性3项规则的设置和实现方式。
1.1 实体完整性
实体( Entity
) 是一个数据对象,是指客观存在并可以相互区分的事物,如一个教师、一个学生或一个雇员等。一个实体在数据库中表现为表中的一条记录。通常情况下,它必须遵守实体完整性规则。
实体完整性规则(Entity Integrity Rule
)是指关系的主属性,即主码(主键)的组成不能为空,也就是关系的主属性不能是空值(NULL
)。关系对应于现实世界中的实体集,而现实世界中的实体是可区分的,即说明每个实例具有唯一性标识。在关系模型中,是使用主码(主键)作为唯一性标识的,若假设主码(主键)取空值,则说明这个实体不可标识,即不可区分,这个假设显然不正确,与现实世界应用环境相矛盾,因此不能存在这样的无标识实体,从而在关系模型中引入实体完整性约束。例如,学生关系(学号、姓名、性别)中,学号
为主码(主键),则 学号
这个属性不能为空值,否则就违反了实体完整性规则。在 MySQL
中,实体完整性是通过 主键约束 和 候选键约束 来实现的。
1.1.1 主键约束
主键可以是表中的某一列,也可以是表中多个列构成的一个组合;其中,由多个列组合而成的主键也称为复合主键。在 MySQL
中,主键必须遵守以下规则:
- 每一个表只能定义一个主键。
- 唯一性原则。主键的值,也称键值,必须能够唯一标识表中的每一行记录,且不能为
NULL
。也就是说,一个表中两个不同的行在主键上不能具有相同的值。 - 最小化规则。复合主键不能包含不必要的多余列。也就是说,当从一个复合主键中删除一列后,如果剩下的列构成的主键仍能满足唯一性原则,那么这个复合主键是不正确的。
- 一个列名在复合主键的列表中只能出现一次。
MySQL
的主键名总是PRIMARY
,就算自己命名了主键约束名也没用。
在 MySQL
中,可以在 CREATE TABLE
或者 ALTER TABLE
语句中,使用 PRIMARY KEY
子句来创建主键约束,其实现方式有以下两种。
1、 作为列的完整性约束。在定义表的某个列的属性时,加上 PRIMARY KEY
关键字实现。
#在创建用户信息表tb_user时,将id字段设置为主键
mysql> CREATE TABLE IF NOT EXISTS tb_user(
-> id INT PRIMARY KEY,
-> username VARCHAR(30),
-> password VARCHAR(30),
-> createtime DATETIME);
Query OK, 0 rows affected, 1 warning (0.00 sec)
#插入数据测试
mysql> CREATE TABLE IF NOT EXISTS tb_user(
-> id INT PRIMARY KEY,
-> username VARCHAR(30),
-> password VARCHAR(30),
-> createtime DATETIME);
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> INSERT INTO tb_user(id,username,`password`) VALUES(1,'amo','amo123');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_user(id,username,`password`) VALUES(2,'jerry','jerry123');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_user;
+----+----------+----------+------------+
| id | username | password | createtime |
+----+----------+----------+------------+
| 1 | amo | amo123 | NULL |
| 2 | jerry | jerry123 | NULL |
+----+----------+----------+------------+
2 rows in set (0.00 sec)
mysql> INSERT INTO tb_user(id,username,`password`) VALUES(1,'paul','paul123');
ERROR 1062 (23000): Duplicate entry '1' for key 'tb_user.PRIMARY'
mysql> INSERT INTO tb_user VALUES(NULL,'paul','paul123',NULL);
ERROR 1048 (23000): Column 'id' cannot be null
mysql> INSERT INTO tb_user(id,username,`password`) VALUES(3,'amo','amo123');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_user;
+----+----------+----------+------------+
| id | username | password | createtime |
+----+----------+----------+------------+
| 1 | amo | amo123 | NULL |
| 2 | jerry | jerry123 | NULL |
| 3 | amo | amo123 | NULL |
+----+----------+----------+------------+
3 rows in set (0.00 sec)
2、 作为表的完整性约束。在定义表的所有列的属性后,加上 PRIMARY KEY(index_col_name,…)
子句实现。
mysql> CREATE TABLE tb_student(
-> id INT,
-> `name` VARCHAR(30),
-> sex VARCHAR(2),
-> classid INT,
-> birthday DATE,
-> PRIMARY KEY(id,classid));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO tb_student(id,`name`,sex,classid) VALUES(1,'Amo','男',2);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_student(id,`name`,sex,classid) VALUES(2,'Amo','男',2);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_student(id,`name`,sex,classid) VALUES(1,'Jerry','男',2);
ERROR 1062 (23000): Duplicate entry '1-2' for key 'tb_student.PRIMARY'
mysql> INSERT INTO tb_student(id,`name`,sex,classid) VALUES(1,'Jerry','男',NULL);
#如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复
ERROR 1048 (23000): Column 'classid' cannot be null
如果主键仅由表中的某一列所构成,那么以上两种方法均可以定义主键约束;如果主键由表中多个列所构成,那么只能用第二种方法定义主键约束。另外,定义主键约束后,MySQL
会自动为主键创建一个唯一索引,默认名为 PRIMARY
。
mysql> SELECT * FROM information_schema.table_constraints WHERE table_name = 'tb_student';
运行上述代码,其结果如下图所示:
MySQL
的主键名总是 PRIMARY
,就算自己命名了主键约束名也没用。如下所示:
mysql> CREATE TABLE tb_student2(
-> id INT,
-> `name` VARCHAR(30),
-> sex VARCHAR(2),
-> classid INT,
-> birthday DATE,
-> CONSTRAINT pk_tb_student2_id_classid PRIMARY KEY(id,classid));
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT * FROM information_schema.table_constraints WHERE table_name = 'tb_student2';
+--------------------+-------------------+-----------------+--------------+-------------+-----------------+----------+
| CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | TABLE_SCHEMA | TABLE_NAME | CONSTRAINT_TYPE | ENFORCED |
+--------------------+-------------------+-----------------+--------------+-------------+-----------------+----------+
| def | mysql_study | PRIMARY | mysql_study | tb_student2 | PRIMARY KEY | YES |
+--------------------+-------------------+-----------------+--------------+-------------+-----------------+----------+
1 row in set (0.00 sec)
当创建主键约束时,系统默认会在所在的列或列组合上建立对应的主键索引(能够根据主键查询的,就根据主键查询,效率更高)。如果删除主键约束了,主键约束对应的索引就自动删除了。如下所示:
#删除主键约束,不需要指定主键名,因为一个表只有一个主键
mysql> ALTER TABLE tb_student2 DROP PRIMARY KEY;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM information_schema.table_constraints WHERE table_name = 'tb_student2';
Empty set (0.00 sec)
#删除主键约束后,非空还存在
mysql> DESC tb_student2;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(30) | YES | | NULL | |
| sex | varchar(2) | YES | | NULL | |
| classid | int | NO | | NULL | |
| birthday | date | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
注意:不要修改主键字段的值。 因为主键是数据记录的唯一标识,如果修改了主键的值,就有可能会破坏数据的完整性。补充:建表后增加主键约束:
1.1.2 自增列:AUTO_INCREMENT
关键字: AUTO_INCREMENT
特点和要求:
- 一个表最多只能有一个自增长列
- 当需要产生唯一标识符或顺序值时,可设置自增长
- 自增长列约束的列必须是键列(主键列,唯一键列)
- 自增约束的列的数据类型必须是整数类型
- 如果自增列指定了
0
和NULL
,会在当前最大值的基础上自增;如果自增列手动指定了具体值,直接赋值为具体值。
错误演示:
mysql> CREATE TABLE temp_employee(
-> eid INT AUTO_INCREMENT,
-> ename VARCHAR(20));
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
mysql> CREATE TABLE temp_employee(
-> eid INT,
-> ename VARCHAR(20) PRIMARY KEY AUTO_INCREMENT);
ERROR 1063 (42000): Incorrect column specifier for column 'ename'
建表时指定自增约束:
CREATE TABLE table_name(
字段名 数据类型 PRIMARY KEY AUTO_INCREMENT,
.....
);
CREATE TABLE table_name(
...
字段名 数据类型 UNIQUE KEY AUTO_INCREMENT, #UNIQUE KEY后续会进行讲解
...
);
建表:
mysql> CREATE TABLE tb_student(
-> id INT PRIMARY KEY AUTO_INCREMENT,
-> `name` VARCHAR(30),
-> sex VARCHAR(2),
-> classid INT,
-> birthday DATE);
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT * FROM tb_student;
Empty set (0.00 sec)
mysql> INSERT INTO tb_student VALUES(1,'Amo','男',1,'1999-10-03');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_student VALUES(NULL,'Crystal','女',1,'1996-08-03');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_student;
+----+---------+------+---------+------------+
| id | name | sex | classid | birthday |
+----+---------+------+---------+------------+
| 1 | Amo | 男 | 1 | 1999-10-03 |
| 2 | Crystal | 女 | 1 | 1996-08-03 |
+----+---------+------+---------+------------+
2 rows in set (0.00 sec)
mysql> INSERT INTO tb_student VALUES(0,'Paul','男',2,'1998-08-03');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_student VALUES(10,'Paul','男',2,'1998-08-03');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tb_student;
+----+---------+------+---------+------------+
| id | name | sex | classid | birthday |
+----+---------+------+---------+------------+
| 1 | Amo | 男 | 1 | 1999-10-03 |
| 2 | Crystal | 女 | 1 | 1996-08-03 |
| 3 | Paul | 男 | 2 | 1998-08-03 |
| 10 | Paul | 男 | 2 | 1998-08-03 |
+----+---------+------+---------+------------+
4 rows in set (0.00 sec)
mysql> DESC tb_student;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(30) | YES | | NULL | |
| sex | varchar(2) | YES | | NULL | |
| classid | int | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
建表后指定自增约束:
mysql> CREATE TABLE tb_student2(
-> id INT PRIMARY KEY,
-> `name` VARCHAR(30),
-> sex VARCHAR(2),
-> classid INT,
-> birthday DATE);
Query OK, 0 rows affected (0.01 sec)
mysql> DESC tb_student2;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(30) | YES | | NULL | |
| sex | varchar(2) | YES | | NULL | |
| classid | int | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
mysql> ALTER TABLE tb_student2 MODIFY id INT AUTO_INCREMENT;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> DESC tb_student2;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | 「MySQL」- 约束详解