MySQL 基础篇(四):表的约束

目录

本文内容概要

[1. 为什么需要约束](#1. 为什么需要约束)

[2. DEFAULT 默认值](#2. DEFAULT 默认值)

[3. NOT NULL 非空约束](#3. NOT NULL 非空约束)

[3.1 NOT NULL 的基本用法](#3.1 NOT NULL 的基本用法)

[3.2 NOT NULL 与 DEFAULT 关系](#3.2 NOT NULL 与 DEFAULT 关系)

[4. UNIQUE 唯一约束](#4. UNIQUE 唯一约束)

[4.1 UNIQUE 的基本用法](#4.1 UNIQUE 的基本用法)

[4.2 UNIQUE 与 NULL](#4.2 UNIQUE 与 NULL)

[4.3 联合唯一约束](#4.3 联合唯一约束)

[5. PRIMARY KEY 主键约束](#5. PRIMARY KEY 主键约束)

[5.1 PRIMARY KEY 的基本使用](#5.1 PRIMARY KEY 的基本使用)

[5.2 联合主键约束](#5.2 联合主键约束)

[5.3 自增长 AUTO_INCREMENT](#5.3 自增长 AUTO_INCREMENT)

[5.3.2 手动指定自增长值](#5.3.2 手动指定自增长值)

[5.3.3 设置自增长起始值](#5.3.3 设置自增长起始值)

[5.3.3 DELETE 与 TRUNCATE 对自增长值的影响](#5.3.3 DELETE 与 TRUNCATE 对自增长值的影响)

[5.4 PRIMARY KEY 与 UNIQUE 的区别](#5.4 PRIMARY KEY 与 UNIQUE 的区别)

[6. 外键约束](#6. 外键约束)

[6.1 为什么需要外键约束](#6.1 为什么需要外键约束)

[6.2 外键约束的基本使用](#6.2 外键约束的基本使用)

[6.3 给外键约束命名](#6.3 给外键约束命名)

[6.4 删除外键约束](#6.4 删除外键约束)

[7. 其他常见列属性](#7. 其他常见列属性)

[7.1 COMMENT 列描述](#7.1 COMMENT 列描述)

[7.2 ZEROFILL 零填充](#7.2 ZEROFILL 零填充)


本文内容概要

本文主要介绍 MySQL 中常见的约束及其使用方式,包括 DEFAULT 默认值、NOT NULL 非空约束、UNIQUE 唯一约束、PRIMARY KEY 主键约束以及 FOREING KEY 外键约束,并结合实际 SQL 操作理解不同约束的作用与使用场景。

除此之外,本文还会补充介绍 AUTO_INCRTMENT 自增长、COMMENT 列描述和 ZEROFILL 零填充等常用列属性,帮助我们进一步掌握 MySQL 数据表的设计与字段约束。

1. 为什么需要约束

在数据库中,我们不仅需要将数据存储起来,还需要保证存储的数据具有一定的正确性、合法性和完整性。

例如:我们创建一张学生信息表:

sql 复制代码
create table student(
    id int,
    name varchar(20),
    gender char(1)
);

如果没有对表中的字段进行任何设置,在实际业务角度,可能发生一下问题:

  • 学生 id 应该用于唯一标识一个学生,不应该出现重复;

  • 学生 id 不应该为空;

  • 学生姓名可能要求必须填写;

  • 某些字段可能需要具有默认值;

  • 不同数据表之间可能需要保证数据的关联关系。

如果这些规则全部依靠程序员在业务代码中进行判断,不仅会增加程序的复杂度,而且一旦某处代码存在细微 BUG,就可能向数据库插入非法数据。因此 MySQL 提供了约束机制,可以直接在数据库层面进行限制。

约束:对数据表中字段的数据进行限制的一系列规则,用于保证数据库中数据的正确性、合法性和完整性。

2. DEFAULT 默认值

在创建数据表时,可以通过 DEFAULT 关键字为字段指定默认值。

sql 复制代码
mysql> create table student(
    -> id int unsigned,
    -> name varchar(20),
    -> gender char(1) default '男'
    -> );
Query OK, 0 rows affected (0.01 sec)

查看表结构:

sql 复制代码
mysql> desc student;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int(10) unsigned | YES  |     | NULL    |       |
| name   | varchar(20)      | YES  |     | NULL    |       |
| gender | char(1)          | YES  |     | 男      |       |
+--------+------------------+------+-----+---------+-------+

其中,gender 字段的默认值被设置为了 '男'。

当插入数据时,如果没有为 gender 字段指定值,MySQL 就会自动使用该字段的默认值:

sql 复制代码
mysql> insert into student (id, name, gender) values (1, '张三', '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student (id, name) values (2, '李四');
Query OK, 1 row affected (0.01 sec)

mysql> insert into student (id, gender) values (3, '女');
Query OK, 1 row affected (0.00 sec)

查询数据:

sql 复制代码
mysql> select * from student;
+------+--------+--------+
| id   | name   | gender |
+------+--------+--------+
|    1 | 张三   | 男     |
|    2 | 李四   | 男     |
|    3 | NULL   | 女     |
+------+--------+--------+

可以看到:

  • 第一条记录显式指定了 gender = '男';

  • 第二条记录没有指定 gender,因此使用默认值 '男';

  • 第三条记录没有指定 name,使用默认值 NULL;

如果没有显式指定 DEFAULT,MySQL 通常会将 NULL 作为其默认值。

NULL 表示该字段当前没有值,它并不是空字符串 '',也不是数字 0。

查看建表语句:

sql 复制代码
mysql> show create table student \G;
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` int(10) unsigned DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL,
  `gender` char(1) DEFAULT '男'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

3. NOT NULL 非空约束

3.1 NOT NULL 的基本用法

在创建数据表时,可以通过 NOT NULL 约束指定某个字段不允许为 NULL。

sql 复制代码
mysql> create table student(
    -> id int unsigned not null,
    -> name varchar(20) not null,
    -> gender char(1)
    -> );
Query OK, 0 rows affected (0.01 sec)

查看数据表结构:

sql 复制代码
mysql> desc student;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int(10) unsigned | NO   |     | NULL    |       |
| name   | varchar(20)      | NO   |     | NULL    |       |
| gender | char(1)          | YES  |     | NULL    |       |
+--------+------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

其中:

  • id 字段的 Null 为 NO,表示该字段不允许为 NULL;

  • name 字段的 Null 为 NO,表示该字段不允许为 NULL;

  • gender 字段的 Null 为 YES,表示该字段允许为 NULL。

接下来插入数据:

sql 复制代码
mysql> insert into student (id, name, gender) values (1, '张三', '男');
Query OK, 1 row affected (0.01 sec)

mysql> insert into student (id, name) values (1, '张三');
Query OK, 1 row affected (0.00 sec)

第二条语句虽然没有指定 gender 字段,但由于 gender 允许为 NULL,因此可以正常插入。

如果没有为被 NOT NULL 约束的字段提供默认值:

sql 复制代码
mysql> insert into student (name, gender) values ('王五', '女');
ERROR 1364 (HY000): Field 'id' doesn't have a default value

由于 id 字段被 NOT NULL 约束,并且没有设置默认值,因此插入失败。

查看当前数据:

sql 复制代码
mysql> select * from student;
+----+--------+--------+
| id | name   | gender |
+----+--------+--------+
|  1 | 张三   | 男     |
|  1 | 张三   | NULL   |
+----+--------+--------+
2 rows in set (0.01 sec)

因此,NOT NULL 约束的作用就是:要求该字段必须具有有效值,不能存储 NULL**。**

需要注意的是,NULL 和空字符串 '' 并不是同一个概念。NOT NULL 只限制字段不能为 NULL,并不会禁止插入空字符串。

查看建表语句:

sql 复制代码
mysql> show create table student \G;
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` int(10) unsigned NOT NULL,
  `name` varchar(20) NOT NULL,
  `gender` char(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

3.2 NOT NULL 与 DEFAULT 关系

NOT NULL 约束本身不会为字段提供默认值。

sql 复制代码
mysql> insert into student (name, gender) values ('小红', '女');
ERROR 1364 (HY000): Field 'id' doesn't have a default value
mysql> insert into student (id, name, gender) values (NULL ,'小红', '女');
ERROR 1048 (23000): Column 'id' cannot be null

这两种错误虽然都与 NOT NULL 字段有关,但产生错误的原因并不相同:

  • 插入数据时省略 NOT NULL 字段:由于该字段没有设置默认值,MySQL 无法确定应该为该字段插入什么值,因此报错。
  • 显示向 NOT NULL 字段插入 NULL:违反了 NOT NULL 非空约束,因此报错

因此需要区分:没有提供默认值 ≠ 显式插入 NULL

前者涉及字段是否存在默认值,后者则违反 NOT NULL 非空约束。

NOT NULL 和 DEFAULT 的联合使用样例

sql 复制代码
mysql> create table student(
    -> id int unsigned,
    -> name varchar(20)^C
mysql> create table student(
    -> id int unsigned not null,
    -> name varchar(20) not null,
    -> gender char(1) not null default '男'
    -> );

mysql> show create table student \G;
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` int(10) unsigned NOT NULL,
  `name` varchar(20) NOT NULL,
  `gender` char(1) NOT NULL DEFAULT '男'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

mysql> insert into student (id, name, gender) values (10, '小华', '女');
mysql> insert into student (id, name) values (11, '小黑');

mysql> select * from student;
+----+--------+--------+
| id | name   | gender |
+----+--------+--------+
| 10 | 小华   | 女     |
| 11 | 小黑   | 男     |
+----+--------+--------+
2 rows in set (0.00 sec)

4. UNIQUE 唯一约束

4.1 UNIQUE 的基本用法

在创建数据表时,可以通过 UNIQUE 约束保证某个字段中的数据具有唯一性,即该字段中不能出现重复的数据。

例如,学生的学号通常应该具有唯一性,可以通过 UNIQUE 对学号字段进行约束。

sql 复制代码
mysql> create table student(
    -> id int unsigned unique,
    -> name varchar(20) not null,
    -> gender char(1) 
    -> );
Query OK, 0 rows affected (0.01 sec)

查看表结构:

sql 复制代码
mysql> desc student;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int(10) unsigned | YES  | UNI | NULL    |       |
| name   | varchar(20)      | YES  |     | NULL    |       |
| gender | char(1)          | YES  |     | NULL    |       |
+--------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

可以看到,id 字段对应的 Key 为 UNI,表示该字段被唯一约束修饰。

向数据表中插入数据:

sql 复制代码
mysql> insert into student values (1, '张三', '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values (2, '李四', '男');
Query OK, 1 row affected (0.00 sec)

此时 id 字段中的数据分别为 1 和 2,不存在重复,因此可以正常插入。

如果再次插入相同的 id:

sql 复制代码
mysql> insert into student values (1, '王五', '男');
ERROR 1062 (23000): Duplicate entry '1' for key 'id'

由于 id 字段被 UNIQUE 约束修饰,而当前数据表中已经存在 id = 1 的记录,因此再次插入相同的数据会违反唯一约束,MySQL 会拒绝此次插入。

因此:UNIQUE 约束保证字段中的非 NULL****数据不能重复。

4.2 UNIQUE 与 NULL

需要注意的是,UNIQUE 约束和 NOT NULL 约束是两个不同的约束。

UNIQUE 负责保证数据的唯一性,但并不会限制字段不能为 NULL。

例如:

sql 复制代码
mysql> insert into student (name, gender) values ('小红', '女');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student (name, gender) values ('小明', '男');
Query OK, 1 row affected (0.00 sec)

查看数据:

sql 复制代码
mysql> select * from student;
+------+--------+--------+
| id   | name   | gender |
+------+--------+--------+
|    1 | 张三   | 男     |
|    2 | 李四   | 男     |
| NULL | 小红   | 女     |
| NULL | 小明   | 男     |
+------+--------+--------+

可以看到,即使 id 字段被 UNIQUE 约束修饰,也仍然可以存在多个 NULL。

这是因为 NULL 表示未知或者不存在的值,在进行唯一性判断时,MySQL 允许唯一索引中存在多个 NULL。

因此:UNIQUE ≠ NOT NULL

如果既要求字段不能为空,又要求字段不能重复,可以同时使用:

sql 复制代码
id int unsigned not null unique

4.3 联合唯一约束

除了可以约束单个字段之外,UNIQUE 还可以同时约束多个字段,这种方式称为联合唯一约束。

例如,存在如下数据表:

sql 复制代码
mysql> create table course(
    -> student_id int unsigned,
    -> course_id int unsigned,
    -> score int,
    -> unique(student_id, course_id)
    -> );
Query OK, 0 rows affected (0.01 sec)

unique(student_id, course_id) 表示 student_id 和 course_id 两个字段组合起来必须具有唯一性。

插入数据:

sql 复制代码
mysql> insert into course values (1, 1001, 90);
Query OK, 1 row affected (0.00 sec)

mysql> insert into course values (1, 1002, 85);
Query OK, 1 row affected (0.00 sec)

mysql> insert into course values (2, 1001, 92);
Query OK, 1 row affected (0.00 sec)

虽然数据中出现了重复的 student_id 和重复的 course_id,但两个字段组成的组合并没有重复,因此可以正常插入。

如果再次插入:

sql 复制代码
mysql> insert into course values (1, 1001, 95);
ERROR 1062 (23000): Duplicate entry '1-1001' for key 'student_id'

此时:

sql 复制代码
student_id = 1
course_id  = 1001

这一组合已经存在,因此违反联合唯一约束。

即联合唯一约束限制的并不是某一个字段单独不能重复,而是:多个字段组合之后的值不能重复。

5. PRIMARY KEY 主键约束

5.1 PRIMARY KEY 的基本使用

在一张数据表中,通常需要使用某个字段唯一标识一条记录,这个字段就可以设置为主键。

MySQL 可以通过 PRIMARY KEY 约束指定数据表的主键。

例如,学生表中的 id 可以作为每个学生的唯一标识:

sql 复制代码
mysql> create table student(
    -> id int unsigned primary key,
    -> name varchar(20) not null,
    -> gender char(1)
    -> );
Query OK, 0 rows affected (0.01 sec)

查看数据表结构:

sql 复制代码
mysql> desc student;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int(10) unsigned | NO   | PRI | NULL    |       |
| name   | varchar(20)      | YES  |     | NULL    |       |
| gender | char(1)          | YES  |     | NULL    |       |
+--------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

可以看到:

  • id 字段的 Key 为 PRI,表示该字段是主键;

  • id 字段的 Null 为 NO,表示主键字段不允许为 NULL。

向数据表中插入数据:

sql 复制代码
mysql> insert into student values (1, '张三', '男');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values (2, '李四', '男');
Query OK, 1 row affected (0.00 sec)

由于两个 id 值不同,因此可以正常插入。

如果再次插入已经存在的主键值:

sql 复制代码
mysql> insert into student values (1, '王五', '男');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

由于 id = 1 已经存在,再次插入相同的主键值会违反主键的唯一性,因此插入失败。

主键也不能为 NULL:

sql 复制代码
mysql> insert into student values (NULL, '小红', '女');
ERROR 1048 (23000): Column 'id' cannot be null

因此,主键必须同时满足:不能重复 + 不能为空

从约束效果上可以将主键理解为:

sql 复制代码
PRIMARY KEY ≈ UNIQUE + NOT NULL

需要注意的是,这只是为了方便理解主键的约束效果,并不代表主键在 MySQL 内部就是简单地由UNIQUE 和 NOT NULL 两个约束组合而成。

注:一张数据表最多只能定义一个 PRIMARY KEY。

例如,下面的定义是不允许的:

sql 复制代码
create table student(
    id int primary key,
    number int primary key,
    name varchar(20)
);

因为一张表不能同时存在两个独立的主键。

但是,一个主键可以由多个字段共同组成,这种主键称为联合主键。

5.2 联合主键约束

有些情况下,单独使用某一个字段无法唯一标识一条记录,此时可以使用多个字段共同组成主键。

例如,一名学生可以选择多门课程,一门课程也可以被多名学生选择:

sql 复制代码
mysql> create table course(
    -> student_id int unsigned,
    -> course_id int unsigned,
    -> score int,
    -> primary key(student_id, course_id)
    -> );
Query OK, 0 rows affected (0.01 sec)

primary key(student_id, course_id) 表示 student_id和 course_id两个字段共同组成主键。

插入数据:

sql 复制代码
mysql> insert into course values (1, 1001, 90);
Query OK, 1 row affected (0.00 sec)

mysql> insert into course values (1, 1002, 85);
Query OK, 1 row affected (0.00 sec)

mysql> insert into course values (2, 1001, 92);
Query OK, 1 row affected (0.00 sec)

虽然 student_id和 course_id单独来看都存在重复,但是两个字段组成的组合并没有重复,因此可以正常插入。

如果再次插入:

复制代码
mysql> insert into course values (1, 1001, 95);
ERROR 1062 (23000): Duplicate entry '1-1001' for key 'PRIMARY'

由于:

复制代码
(student_id, course_id) = (1, 1001)

这个组合已经存在,因此违反了联合主键的唯一性。

即:联合主键要求组成主键的多个字段组合后的值具有唯一性。

5.3 自增长 AUTO_INCREMENT

在创建数据表时,经常会使用一个整数类型的字段作为主键,例如学生表中的 id:

sql 复制代码
create table student(
    id int unsigned primary key,
    name varchar(20) not null
);

由于主键要求数据唯一,因此每次插入数据时,都需要手动为 id 指定一个不同的值:

sql 复制代码
insert into student values(1, '张三');
insert into student values(2, '李四');
insert into student values(3, '王五');

如果数据量非常大,每次都手动维护主键值显然比较麻烦。

MySQL 提供了 AUTO_INCREMENT 属性,可以让整数类型的字段自动增长。

sql 复制代码
create table student(
    id int unsigned primary key auto_increment,
    name varchar(20) not null
);

此时插入数据时,就可以不用手动指定 id:

sql 复制代码
insert into student(name) values('张三');
insert into student(name) values('李四');
insert into student(name) values('王五');

查询数据:

sql 复制代码
mysql> select * from student;
+----+--------+
| id | name   |
+----+--------+
|  1 | 张三   |
|  2 | 李四   |
|  3 | 王五   |
+----+--------+

可以看到,MySQL 会自动为 id 字段分配递增的值。

5.3.1 AUTO_INCREMENT 的特点

  1. 通常作用于整数类型字段。

  2. 一张表只能存在一个 AUTO_INCREMENT 字段。

  3. AUTO_INCREMENT 字段必须建立索引,因此实际开发中通常将其设置为主键。

sql 复制代码
id int unsigned primary key auto_increment
  1. 默认情况下,自增长值从 1 开始,每次增加 1。

  2. 插入数据时,如果不指定自增长字段的值,MySQL 会自动生成。

例如:

sql 复制代码
insert into student(name) values('小明');

也可以写成:

sql 复制代码
insert into student values(NULL, '小红');

对于 AUTO_INCREMENT 字段插入 NULL 时,MySQL 会自动生成下一个自增长值。

5.3.2 手动指定自增长值

虽然字段使用了 AUTO_INCREMENT ,但是仍然可以手动指定一个合法的值:

sql 复制代码
insert into student values(10, '小刚');

此时 id = 10。

如果当前自增长计数小于 10,那么之后继续插入数据时,自增长值通常会从更大的值继续增长:

sql 复制代码
insert into student(name) values('小李');

此时得到:id = 11

因此,AUTO_INCREMENT 并不是限制用户不能手动插入数据,而是在用户没有指定字段值时,由 MySQL 自动生成一个值。

5.3.3 设置自增长起始值

创建表时,也可以指定自增长的起始值:

sql 复制代码
create table student(
    id int unsigned primary key auto_increment,
    name varchar(20) not null
) auto_increment = 100;

此时第一条数据的 id 将从 100 开始:

sql 复制代码
insert into student(name) values('张三');
sql 复制代码
id = 100

也可以通过 ALTER TABLE 修改下一次自增长使用的值:

sql 复制代码
alter table student auto_increment = 200;
5.3.3 DELETE 与 TRUNCATE 对自增长值的影响

使用 DELETE 删除数据后,自增长计数通常不会改变。

例如原来的数据为:

sql 复制代码
1
2
3

执行:

sql 复制代码
delete from student;

再次插入:

sql 复制代码
insert into student(name) values('张三');

新数据的 id 通常会继续向后增长,而不是重新变成 1。

而使用:

sql 复制代码
truncate table student;

清空表时,会重新初始化自增长计数,下一次插入数据通常会重新从 1 开始。

注意:AUTO_INCREMENT 的作用是自动生成递增值,并不代表生成的值一定连续。例如数据被删除、事务回滚等情况下,自增长序列可能出现空缺。因此不要将 AUTO_INCREMENT 理解为"保证编号连续"。

5.4 PRIMARY KEY 与 UNIQUE 的区别

primary key 和 unique 都可以保证数据具有唯一性,但两者之间仍然存在区别。

对比项 PRIMARY KEY UNIQUE
是否保证唯一 是 是
是否允许 NULL 不允许 可以允许 NULL
一张表可以有几个 最多一个 可以有多个
主要作用 唯一标识一条记录 保证字段数据不重复

主键主要是用来标识唯一性字段,唯一键主要是用来处理业务逻辑上的唯一性!

6. 外键约束

6.1 为什么需要外键约束

在实际开发中,一张数据表通常无法描述所有的数据,不同的数据之间往往存在一定的关联关系。

例如:学校中会存在学生和班级 ---- 班级表和学生表

| 班级表(class) | class_id | class_name | |----------|------------| | 1 | 计算机1班 | | 2 | 计算机2班 | 学生表(student) | id | name | class_id | |----|------|----------| | 1 | 张三 | 1 | | 2 | 李四 | 1 | | 3 | 王五 | 2 | | |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---|
| | |
| | |

学生表中的 class_id 用于表示当前学生所属哪个班级。

如果只是存在这两种表,但没有任何限制:就可能会出现下面这种情况:

sql 复制代码
insert into student values(4, '赵六', 100);
delete from class where id=1;
  1. 构建一个学生的基本信息时,插入一个不存在的班级 id
  2. 删除班级 id 时,有学生表依旧关联该班级 id

此时,为了保证两张表之间数据的完整性,MySQL 提供了外键约束。

6.2 外键约束的基本使用

外键约束主要用于建立两张表之间的关联关系,并保证关联数据的合法性。

通常将被引用的表成为父表,引用其他表的表成为子表。

在上述例子中:class 为父表,student 为子表。

创建班级表和学生表:

sql 复制代码
create table class(
    class_id int primary key,
    class_name varchar(20) not null
);

create table student(
    id int primary key auto_increment,
    name varchar(20) not null,
    class_id int,
    foreign key(class_id) references class(class_id)
);

插入数据:

sql 复制代码
mysql> insert into class values(1, '计算机1班');
Query OK, 1 row affected (0.01 sec)

mysql> insert into class values(2, '计算机2班');
Query OK, 1 row affected (0.00 sec)

mysql> select * from class;
+----------+---------------+
| class_id | class_name    |
+----------+---------------+
|        1 | 计算机1班     |
|        2 | 计算机2班     |
+----------+---------------+
2 rows in set (0.00 sec)

insert into student (name, class_id) values ('张三', 1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into student (name, class_id) values('李四', 100);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`class_id`))

mysql> delete from class where class_id=2;
Query OK, 1 row affected (0.01 sec)

mysql> delete from class where class_id=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`class_id`))

插入失败原因:子表外键字段的值,必须能够在父表中存在。

删除失败原因:父表中字段被子表所引用。如果父表修改被引用数据也会失败。

注:此处引用,一定是被子表中所占用,就相当于例子中的班级 id=1 被占用,但班级 id=2 未被占用,父表可以对其删除和修改。

建表 SQL 语句:

sql 复制代码
mysql> show create table student \G;
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `class_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `class_id` (`class_id`),
  CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`class_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

6.3 给外键约束命名

创建外键时,也可以显式指定外键约束的名字。如果不指定,MySQL 会默认生成。

sql 复制代码
create table student(
    id int primary key auto_increment,
    name varchar(20) not null,
    class_id int,
    constraint fk_student_class
    foreign key(class_id)
    references class(class_id)
);

show create table student \G;
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `class_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_student_class` (`class_id`),
  CONSTRAINT `fk_student_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`class_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

fk_student_class 就是当前外键约束的名称。

显示命名外键的好处:删除或者管理外键时更加方便。

6.4 删除外键约束

删除外键时,需要通过外键约束名称进行删除:

sql 复制代码
alter table student drop foreign key fk_student_class;

7. 其他常见列属性

前面介绍的 DEFAULT、NOT NULL、UNIQUE、PRIMARY KEY、FOREIGN KEY 主要用于对数据进行约束,除此之外,在定义字段时还可以使用一些其他属性。

7.1 COMMENT 列描述

在创建数据表时,可以通过 COMMENT 为字段添加描述信息,用于说明当前字段的含义。

基本语法:字段名 数据类型 其他属性 comment '字段描述'

sql 复制代码
create table student(
    id int unsigned primary key auto_increment comment '学生编号',
    name varchar(20) not null comment '学生姓名',
    age tinyint unsigned comment '学生年龄'
);

desc student;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type                | Null | Key | Default | Extra          |
+-------+---------------------+------+-----+---------+----------------+
| id    | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20)         | NO   |     | NULL    |                |
| age   | tinyint(3) unsigned | YES  |     | NULL    |                |
+-------+---------------------+------+-----+---------+----------------+

show create table student \G;
*************************** 1. row ***************************
       Table: student
Create Table: CREATE TABLE `student` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '学生编号',
  `name` varchar(20) NOT NULL COMMENT '学生姓名',
  `age` tinyint(3) unsigned DEFAULT NULL COMMENT '学生年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

show full columns from student \G;
*************************** 1. row ***************************
     Field: id
      Type: int(10) unsigned
 Collation: NULL
      Null: NO
       Key: PRI
   Default: NULL
     Extra: auto_increment
Privileges: select,insert,update,references
   Comment: 学生编号
*************************** 2. row ***************************
     Field: name
      Type: varchar(20)
 Collation: utf8_general_ci
      Null: NO
       Key: 
   Default: NULL
     Extra: 
Privileges: select,insert,update,references
   Comment: 学生姓名
*************************** 3. row ***************************
     Field: age
      Type: tinyint(3) unsigned
 Collation: NULL
      Null: YES
       Key: 
   Default: NULL
     Extra: 
Privileges: select,insert,update,references
   Comment: 学生年龄

COMMENT 并不会影响字段中实际存储的数据,它主要是用来提高表结构的可读性。对于结构比较复杂的数据表,通过字段描述可以更加直观理解每个字段的作用。

注:字段描述需要通过查看建表语句或者查看字段的详细信息查看,不能通过 desc 查看。

7.2 ZEROFILL 零填充

ZEROFILL 是 MySQL 数值类型曾经提供的一种显示属性。

它的主要作用是:当数值实际显示宽度不足指定宽度时,在数值左侧使用 0 进行填充。

例如:

sql 复制代码
create table test(
    id int(5) zerofill
);

insert into test values (12);
insert into test values (123);
insert into test values (123456);

select * from test;
+----------+
| id       |
+----------+
|    00012 |
|    00123 |
| 12344444 |
+----------+

其中 int(5) 中的 5 表示的是显示宽度,而不是 INT 类型能够存储的数据位数,当插入的数据显示宽度不足指定宽度时,在数组左侧使用 0 进行填充,当超过指定宽度时,正常显示。

sql 复制代码
show create table test \G;
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `id` int(5) unsigned zerofill DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

如果一个数值字段使用了 zerofill,MySQL 会自动为该字段添加 unsigned 属性。

补充说明:ZEROFILL 已不推荐使用

MySQL 官方已经将:ZEROFILL 以及整数类型的显示宽度标记为 Deprecated(弃用),未来版本可能移除相关支持。官方建议可以使用 LPAD() 完成补零显示,或者直接使用 CHAR类型保存需要固定格式的内容。因此对于 ZEROFILL:了解其作用和历史用法即可,在新的数据库设计中一般不建议继续使用。

相关推荐
阳光九叶草LXGZXJ1 小时前
达梦数据库-学习-71-存过执行过程中重建存过影响验证
linux·运维·数据库·sql·学习
傲世仙尊1 小时前
MySQL上手-库与表的操作编码校验集与备份还原
数据库·mysql
H.莓飛1 小时前
【数据结构】堆
linux·数据结构·算法
Ruiery1 小时前
Linux 6.6内核 CPU 深度解析(四):中断与 IPI — 一个 CPU 怎么“喊“另一个 CPU
linux·运维·服务器
吠品1 小时前
DicomViewer24 的 CI 又红了:MPR 测试偶发失败排查记
java·服务器·前端
志栋智能2 小时前
安全超自动化如何支持快速安全扩容?
运维·服务器·数据库·架构·自动化
木卫二号Coding10 小时前
推荐Linux统计文件大小并操作删除工具-ncdu
linux·运维·服务器
gb421528710 小时前
向量数据库多模态特性
数据库
泡海椒10 小时前
数据占比展示:jquick-pdf饼图动态数据渲染PDF教程
数据库·oracle·pdf