本篇目标:

  1. 了解什么是表的约束,以及约束在数据库中的作用。
  2. 掌握 nullnot null 约束的使用。
  3. 掌握 default 默认值约束的使用。
  4. 掌握 comment 字段说明的使用。
  5. 掌握 zerofill 属性的基本特点。
  6. 掌握 primary key 主键约束及主键自增长。
  7. 掌握 unique 唯一约束的使用。
  8. 掌握 foreign key 外键约束及表之间的关联关系。
  9. 理解各种约束之间的区别,并能够根据实际需求设计合理的表结构

一.表的约束

1.空属性

空属性用于规定表中的某个字段是否允许存储 null

在 mysql 中,空属性主要包括

  • null:允许字段为空。
  • not null:不允许字段为空。

注意:数据库字段基本都是默认字段为空,然而实际开发时,要尽量保证字段不为空,因为数据为空没办法参与运算,例如:

案例: 例如我们创建一个班级表,包含班级名和班级所在的教室。

站在正常的业务逻辑中:

如果班级没有名字,你不知道你在哪个班级 ;如果教室名字可以为空,就不知道在哪上课, 所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这 就是“约束”

mysql> create table myclass(
    -> class_name varchar(20) not null,
    -> class_room varchar(10) not null
    ->);

如图:

可以看出,myclass中的class_name和class_room是不可以为空的,需要有默认值,但是这个下面再讲吧。

2.默认值

概念:插入数据时,如果没有为某个字段指定值,mysql 就会自动使用提前设置好的值。

使用 default 设置字段的默认值。

基本语法:

字段名 数据类型 default 默认值

实例演示:

mysql> create table tt10 (
    -> name varchar(20) not null,
    -> age tinyint unsigned default 0,
    -> sex char(20) default '男' not null
    -> );

如图:

接下来,就是插入数据了,

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

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

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

运行结果:

可以看出如果如果插入数据时明确指定了字段的值,那么数据库将使用这个指定的值,而不会采用预设的默认值;没有默认值但是有not null的不可以省略;有默认值也有not null,但是没有指定字段值,也可以使用这个默认值。

3.列描述

概念:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA 来进行了解。

基本语法:

字段名 数据类型 comment '列描述'

案例使用:

mysql> create table tt12(
    -> name varchar(20) not null comment '姓名',
    -> age tinyint unsigned default 0 comment '年龄',
    -> sex char(2) default '男' comment '性别'
    -> );

通过show可以看到:

mysql> show create table tt12\G;
*************************** 1. row ***************************
       Table: tt12
Create Table: CREATE TABLE `tt12` (
  `name` varchar(20) NOT NULL COMMENT '姓名',
  `age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',
  `sex` char(2) DEFAULT '男' COMMENT '性别'
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

comment 不仅可以描述字段,也可以描述整张表,例如:

mysql> create table student(
    -> id int comment '学生编号',
    -> name varchar(20) comment '学生姓名'
    -> )comment='学生信息表';

通过show可以看到:

4.zerofill

概念:zerofill 称为零填充属性,用于在数值的显示位数不足时,在数字左侧自动补 0

字段名 int(显示宽度) zerofill

实例演示:

mysql> create table class(
    -> id int(10) zerofill,
    -> name varchar(20)
    -> );

mysql> insert into class values(10,123);

通过select即可查看,如图:

id显示宽度是 10,而数字 10 只有两位,因此左侧补充8个 0

zerofill 只是控制显示效果,数据库中实际保存的仍然是数字 12,而不是字符串 '00012'。

验证:

select id + 0 from student;

注意:数值字段使用 zerofill 后,mysql 会自动为该字段添加 unsigned 属性,因此该字段不能

存储负数,实例如图:

mysql> insert into class values(-1,123);

如果我们的数字超过了这个显示长度是不会补0的。

5.主键

主键使用 primary key 表示,用于唯一标识表中的一条记录。

主键具有以下特点:

  • 主键值不能重复
  • 主键值不能为 null
  • 一张表只能有一个主键
  • 一个主键可以由一个字段或者多个字段组成

使用:创建主键时,可以直接在字段后面添加 primary key。

实例使用:

mysql> create table t1( id int primary key, name varchar(20) );

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

mysql> insert into t1 values(2,'张三');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t1 values(3,'张三');
Query OK, 1 row affected (0.00 sec)

我们可以插入多个name为张三,这是因为name没有被设置为primary key,也无法和id一起设置成主键,但是如果我们再插入一个id为3的呢?

就会发现这个会报错的。

并且主键也不可以为null,实例:

insert into t1 values(null, '赵六');

如图:

一个主键也可以由多个字段共同组成,称为复合主键,实例:

mysql> create table score(
    -> student_id int,
    -> course_id int,
    -> score int,
    -> primary key(student_id,course_id)
    -> );

运行结果:

可以看出下面的数据可以同时存在

student_id    course_id
1             1
1             2
2             1

但是下面两条数据不能同时存在:

1    1
1    1

因为两个字段组成的主键完全相同

注意:一张表仍然只有一个主键,只不过这个主键可以由多个字段共同组成。

6.自增长

概念:自增长使用 auto_increment 表示。当插入数据时没有指定该字段的值,mysql 会自动生成一个递增的数值。

自增长的特点:

<1>.任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)。

<2>.自增长字段必须是整数。

<3>.一张表最多只能有一个自增长。

实例演示:

mysql> create table t2( id int auto_increment primary key, name varchar(20) );

然后我们插入数据时插入数据时不指定 id,看看会有什么惊喜?如图:

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

mysql> insert into t2 (name) values('李四');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t2 (name) values('王五');
Query OK, 1 row affected (0.00 sec)

运行结果

而且自增长字段也可以手动指定数值,如图:

mysql> insert into t2 (id,name) values(10,'王五');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t2 (name) values('王五');
Query OK, 1 row affected (0.00 sec)

运行结果:

可以看出,之后再自动插入数据,通常会从更大的值继续增长。

创建表时也可以设置自增长的起始值,实例:

mysql> create table t3( id int primary key auto_increment, name varchar(20) )auto_increment=100;
Query OK, 0 rows affected (0.00 sec)

第一条数据的 id 通常从 100 开始。

也可以修改已有表的自增长值:

alter table t3 auto_increment=100;

删除数据后不会自动补充编号,例如:

假设表中的编号为:

1  2  3

我们删除 id=3 的数据:

delete from student where id=3;

再次插入数据时,生成的编号通常是 4,不会重新使用 3

所以,自增长只能保证自动生成编号,不能保证编号永远连续

7.唯一键

一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键,而唯一键就可以解决表中有多个字段需要唯一性约束的问题

唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较。

关于唯一键和主键的区别: 我们可以简单理解成,主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复。乍一听好像没啥区别,我们举一个例子

假设一个场景(当然,具体可能并不是这样,仅仅为了帮助大家理解)
比如在公司,我们需要一个员工管理系统,系统中有一个员工表,员工表中有两列信息,一个身份证号码,一
个是员工工号,我们可以选择身份号码作为主键。
而我们设计员工工号的时候,需要一种约束:而所有的员工工号都不能重复。
具体指的是在公司的业务上不能重复,我们设计表的时候,需要这个约束,那么就可以将员工工号设计成为唯
一键。
一般而言,我们建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对
主键做过大的调整。

使用:直接在字段后添加 unique。

实例演示

mysql> create table user(
    -> id int primary key auto_increment,
    -> name varchar(20),
    -> phone varchar(20) unique
    -> );

接下来,就是插入数据了,

mysql> insert into user values(null, '张三', '123456');
Query OK, 1 row affected (0.00 sec)

mysql> insert into user values(null, '李四', '654321');
Query OK, 1 row affected (0.00 sec)

mysql> insert into user values(null, '王五', '123456');
ERROR 1062 (23000): Duplicate entry '123456' for key 'phone'

mysql> insert into user (id,name) values(null, '王五');
Query OK, 1 row affected (0.00 sec)

可以看出,插入相同的数据phone为'123456'时会报错,运行结果

当然,多个字段可以共同组成一个唯一键,例如:

mysql> create table t4(
    -> id int primary key auto_increment,
    -> student_id int,
    -> course_id int,
    -> score int,
    -> unique(student_id,course_id)
    -> );

这表示 student_idcourse_id 的组合不能重复。

下面的数据可以同时存在:

student_id    course_id
1             1
1             2
2             1

但是下面两条数据不能同时存在:

1    1
1    1

8.外键

外键使用 foreign key 表示,用于建立两张表之间的关联,并保证关联数据的完整性。

例如:

  • class 表保存班级信息。
  • student 表保存学生信息。
  • 每个学生所属的班级必须在 class 表中真实存在

其中:

  • class 是父表。
  • student 是子表。
  • student 表中的 class_id 是外键。
  • class 表中的 id 是被引用字段。

创建父表

mysql> create table t5(
    -> id int primary key,
    -> name varchar(20) not null
    -> );

接下来创建子表:

mysql> 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(id)
    -> );

其中:

constraint fk_student_class

用于指定外键约束的名称

foreign key(class_id)

表示 student 表中的 class_id 是外键字段。

references class(id)

表示该字段引用 class 表中的 id

先在父表插入几个数据:

mysql> insert into t5 values(1, '通信101');
Query OK, 1 row affected (0.00 sec)

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

再向子表中插入数据:

mysql> insert into student values(null, '张三', 1);

因为班级编号 1 已经存在,所以插入成功。

如果插入一个不存在的班级编号

insert into student values(null, '李四', 10);

那么mysql 会报错,因为父表中不存在 id=10 的班级,如图:

假设存在下面的学生:

张三所属班级编号为1

如果直接删除父表中的班级 1

delete from class where id=1;

mysql 通常会拒绝删除,因为该班级仍然被 student 表中的数据引用。

首先我们承认,这个世界是数据很多都是相关性的。

理论上,上面的例子,我们不创建外键约束,就正常建立学生表,以及班级表,该有的字段我们都有。
此时,在实际使用的时候,可能会出现什么问题?
有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中?

比如学校只开了学霸100班,学霸101班,但是在上课的学生里面竟然有学霸102班的学生(这个班目前并
不存在),这很明显是有问题的。

因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题。
解决方案就是通过外键完成的。建立外键的本质其实就是把相关性交给mysql去审核了,提前告诉mysql
表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入。

总结:

本文系统介绍了MySQL中表约束的概念与应用,重点讲解了8种核心约束及其使用场景:

1. not null约束:强制字段非空,确保数据完整性

2. default约束:为字段设置默认值,简化数据插入

3. comment描述:为字段/表添加说明文档,提高可维护性

4. zerofill属性:数值显示宽度不足时自动前补零

5. primary key主键:唯一标识记录(非空、唯一、单表唯一)

6. auto_increment自增长:自动生成递增值(需配合主键/索引)

7. unique唯一键:保证字段业务唯一性(允许多个NULL值)

8. foreign key外键:维护表间引用完整性(需先创建父表)

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐