首页
看点啥
插画图片
首页 科技看点 MySQL数据库表的约束深度讲解实用指南

MySQL数据库表的约束深度讲解实用指南

2026-10-24 0

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“MySQL数据库表的约束深度讲解”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。

前言

在上一篇的文章中我们轻松的了解了对表的操作,也认识了在MySQL中的数据类型.

但是在上一篇文章中我们遗留了一些问题

今天我们来详细的讲解一下这个表中的知识点.

这些都是对表的约束.

理解这一步时,表的约束很多,这里主要介绍如下所示几个: null/not null,default, comment, zerofill,primary key,auto_increment,unique key。

表的约束

空属性

在上述图片中的第三列中我们能够看到这样的字段

Null
yes
yes

这就是代表的这个字段的填写是能够为空的也就是能够是NULL

create table test1 (
    -> name varchar(20),
    -> class varchar (20) not null
    -> );

现在我们新建出的表的结构如下所示图:

我们来插入一组数据

insert into test1 values (NULL,'高三二班');

能够看到的是name这个字段是能够是空的

但是class这一行是不被允许的.

insert into test1 values (NULL,NULL);
ERROR 1048 (23000): Column 'class' cannot be null

空和空白的区别

类型含义类比
NULL“未知” 或 “不存在”。表示该字段没有值,暂时不知道是什么。相当于一个空杯子,里面有没有水不知道(未知状态)。
空字符串 ''“确定有值,但这个值就是空”。表示我知道这个字段的内容,但内容长度为0。相当于一个明确的空瓶子,我知道里面是空的。
空白(空格)“有值,且值是空格字符”。即 ' ' 或 ' ',它是一个长度为1或以上的非空字符串。相当于瓶子里装满了空气,它是有内容的(内容是不可见的空格)。

举个例子:

在孙悟空没有被菩提祖师点化之前,他的名字就是空白,但是不是NULL.如果是NULL的时候就代表这猴子查无此人了.当被赋予了名字之后空白名字就被覆盖成为了孙悟空.

默认值

在C++的语法中我们知道函数参数是有一个叫做缺省值的东西的,也就是我们不向函数传参的时候他的参数会默认是缺省值的.

在这里是相同的含义的.

insert into test1 (name) values ('张三');
ERROR 1364 (HY000): Field 'class' doesn't have a default value

在上述的表结构中,两个字段的默认值都是NULL.所以我们不填写class的时候默认是NULL的.

但是我们有设置了class不为NULL所以出现了错误.

 alter table test1 modify class varchar (20)  default '高三二班';

现在我们修改了class的默认值,让他不是NULL.

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

现在插入数据即使一个合法的操作了.

列描述

这个呢就是能够类比于C++中的注释来看.

create table test1 (
 name varchar (20) comment '用户名字',
 class varchar (20) comment '用户班级'
);

但是用desc是看不到这个注释的.

我们能够看我们新建表的所有的操作来看

show create table [名称];
show create table test1;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test1 | CREATE TABLE `test1` (
  `name` varchar(20) DEFAULT NULL COMMENT '用户名字',
  `class` varchar(20) DEFAULT NULL COMMENT '用户班级'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

zerofill

 create table test1 ( id int(3) zerofill  not null, name varchar (20) not null );

我们看到在新建的时候这个int类型怎么还有一个3?

这就是传说中的zerofill的参数.

名副其实的就是补零.

select * from test1;
+-----+--------+
| id | name |
+-----+--------+
| 001 | 张三 |
+-----+--------+

但是当实际的位数大于我们设置的宽度的时候他的行为就是什么都不做.

主键

主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个 主键;主键所在的列通常是整数类型。

通俗的来说就是:

主键是来标识一个用户的唯一性的,类似于我们的身份证,身份证是不可能有重复的.

create table test1 (
    -> id int primary key not null comment '学号',
    -> name varchar (20) not null
    -> );
 insert into test1 value 
    -> (1,'j');

我们现在来尝试插入重复的id

 insert into test1 value  (1,'k');
ERROR 1062 (23000): Duplicate entry '1' for key 'test1.PRIMARY'

我们的操作是不被允许的,所以主键是具有唯一性的.

我们也是能够删除主键的.

alter table test1 drop primary key;
desc test1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+

删除之后这个id字段同时没有消失而是删除了主键的属性而已.

那么怎么追加主键呢?

alter table test1 add primary key (id);
desc test1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+

但是在特殊的情况下一个字段是不能确认用户的唯一性的,需多个字段来确认用户的唯一.

比如我们来描述一个陌生人:

戴眼镜与否,身材,穿着....

这时候我们就需采用复合主键了

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

现在我们新建的表主键就是一个复合主键.

 insert into test1 values 
    -> (1,'张三',1);

insert into test1 values (1,'李四',2);
Query OK, 1 row affected (0.01 sec)

当我们插入的数据id和class都是一样的时候他才会报错

 insert into test1 values  (1,'李四',2);
ERROR 1062 (23000): Duplicate entry '1-2' for key 'test1.PRIMARY'

自增长

auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值 +1操作,得到一个新的不同的值。通常和主键搭配采用,作为逻辑主键。

自增长的特点:

  • 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
  • 自增长字段必须是整数
  • 一张表最多只能有一个自增长
create table test1 (
    -> id int not null primary key auto_increment,
    -> name varchar (20) not null
    -> );
insert into test1 (name) values ('张三');


select * from test1;
+----+--------+
| id | name |
+----+--------+
| 1 | 张三 |
+----+--------+

我们继续插入数据

insert into test1 (name) values ('李四');


select * from test1;
+----+--------+
| id | name |
+----+--------+
| 1 | 张三 |
| 2 | 李四 |
+----+--------+

的确他是会自增长的.

insert into test1  values (100,'王五');

insert into test1 (name) values ('赵六');

select * from test1;
+-----+--------+
| id | name |
+-----+--------+
| 1 | 张三 |
| 2 | 李四 |
| 100 | 王五 |
| 101 | 赵六 |
+-----+--------+

我们现在删除这个赵六这个数据.

DELETE FROM test1 WHERE id = 101;

 select * from test1;
+-----+--------+
| id | name |
+-----+--------+
| 1 | 张三 |
| 2 | 李四 |
| 100 | 王五 |
+-----+--------+

现在插入的话自增过后的id是多少

insert into test1 (name) values ('赵六');

select * from test1;
+-----+--------+
| id | name |
+-----+--------+
| 1 | 张三 |
| 2 | 李四 |
| 100 | 王五 |
| 102 | 赵六 |
+-----+--------+

能够发现的是这个自增的id不是现在存在id的最大值的++,而是存在过的最大值的自增.

这是怎么实现的?

 SHOW TABLE STATUS LIKE 'test1'\G
*************************** 1. row ***************************
           Name: test1
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 4
 Avg_row_length: 4096
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 0
 Auto_increment: 103
    Create_time: 2026-08-26 17:41:26
    Update_time: 2026-08-26 17:47:19
     Check_time: NULL
      Collation: utf8mb4_0900_ai_ci
       Checksum: NULL
 Create_options:
        Comment:

在表中都是有记录的.

唯一键

唯一键代表的就是这个字段不能在同一个表中存在相同的值.

这样听起来的效果于主键是相同的.

但是他们还是有不同的地方的.

主键(PRIMARY KEY)唯一键(UNIQUE KEY)
一句话表的"身份证号"表的"手机号"
数量每张表只能有1个每张表能够有多个
是否允许NULL 绝对不允许 允许有NULL(多个NULL不冲突)
是否自动建索引 自动新建 自动新建
业务含义通常无业务含义(如自增ID)有业务含义(如手机号、邮箱)

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

create table test1 (
    -> id int unique comment '可以为空,但是不能重复,学号',
    -> name varchar (20) not null
    -> );
insert into test1 values (1,'张三');
Query OK, 1 row affected (0.00 sec)

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

mysql> insert into test1 values (2,'李四');
ERROR 1062 (23000): Duplicate entry '2' for key 'test1.id'

能够看到的是唯一键是不能够重复的.

外键

我们先不解释什么是外键我们先来轻松的新建出两个表.

一个学生表,一个班级表

create table stu (
    -> id int not null,
    -> name varchar(20) not null,
    -> class_id int not null
    -> );
create table class (
    -> class_id int not null,
    -> class_name varchar (20) not null
    -> );

现在我们先新建一些班级.

insert into class values 
    -> (100,'C++班级'),
    -> (101,'Java班级');

现在我们有了两个班级了现在就是输入学生的数据了

insert into stu values 
    -> (1,'张三',100),
    -> (2,'李四',101);

但是如果是这样的数据呢?

insert into stu values  (1,'张三',102);
Query OK, 1 row affected (0.01 sec)

有点不对劲啊,我们的班级哪里有102班这不是错误数据吗?

但是数据库并没有限制我们的操作.

这时候我们该怎么处理?

这时候就需两个表结构建立起联系了.

怎么建立起联系呢?

外键就能够起到这个桥梁的作用了.

foreign key (当前表的字段) references [建立连接表的名称] (字段);

alter table stu add primary key (class_id);
alter table class add primary key (class_id);
delete from stu where class_id=102;
alter table stu add foreign key (class_id) references class(class_id);

首先建立外键需两个即将建立的字段是唯一键或者是主键.

这样按道理说我们的是能够建立起外键的,因为我们之前的操作导致stu表中存在不合理的数据,所以我们需删除这个数据.

建立外键.

这样我们再插入不合理的数据的时候就会被拦截了.

insert into stu values (3,'王五',102);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`jiao`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`class_id`))

总结

理解这一步时,总的来说,mysql中的约束适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。

喜欢(0)

上一篇

查询Oracle 数据库用户权限的做法实用指南

下一篇

Oracle数据库中字符串截取技巧整理的两种实现方式方式实用指南

猜你喜欢