【MySQL】表的约束(上)

文章目录

  • [1. 空属性(非空约束)](#1. 空属性(非空约束))
  • [2. 默认值(default约束)](#2. 默认值(default约束))
  • [3. 非空约束与default约束对比](#3. 非空约束与default约束对比)
  • [补充1: 列描述(comment)](#补充1: 列描述(comment))
  • 补充2:zerofill(0填充)

什么是表的约束呢?我们先来简单的理解一下

如果我们往一个文件里面写入数据,我可以随便写,想写什么写什么,这就是没有约束。
而数据库中建立的表,我们往里面插入数据,是有约束,即不能随便想插入什么就插入什么。
如何理解?
你可以把数据库的表想象成一张 Excel 表格,用来记录信息,比如一个"员工信息表"。
表的"约束",就是你在设计这张表格时,提前定好的 "填写规则 "。它的目的是为了保证你以后往表里添加或修改数据时,数据是可预期的,完整的。比如有一列是性别,那你就只能填男和女,不能随便填别的,比如填成了年龄,身高体重等。填别的就会被拦截。
所以,表中就有各种的约束,通过约束,使得我们未来插入表中的数据是完整的,符合预期的。通过约束,倒逼使用者,插入正确的数据。反过来,站在MySQL的视角,凡是插入进来的数据,都是符合约束的。
约束的最终目标:保证数据的完整性和可预期性。

简单总结一下:

表的约束(Table Constraints)是关系型数据库中用于强制实施数据完整性规则(Data Integrity Rules)的机制。它们是在表级别定义的规则,用于限制表中数据的值,确保数据库中的数据满足预定义的业务逻辑和一致性要求。
(等我们把表的约束讲完之后大家可以回过头来再理解这个概念)

表的约束很多,这里主要介绍如下几个:

null/not null,default, comment, zerofill,primary

key,auto_increment,unique key 。

1. 空属性(非空约束)

两个值:null(空---默认运行为空)和not null(非空)

如果某一列在将来插入时不允许为空,即必须插入有效值(不允许插入空),则可以将这一列的属性带上not null,若允许为空,则属性带上null,不设置,默认允许为空

案例:创建一个班级表,包含两列,班级名和班级所在的教室,两个字段都不允许为空,即一个班级一定有对应的教室,一个教室一定被分配给特定的班级。

建表:
create table class( class_name varchar(20) not null, class_room varchar(20) not null, other varchar(20) );


即前两列我们必须插入有效数据(不能插入空) ,第三列可以插入空或者不插入(默认值为空),当然如果插入了那就放我们插入的值
试一下

前两列我们都插入了数据(当然也必须插入,因为不允许为空),第三列我们第二次没有插入,但我们看到默认填充了NULL,第三列也允许为空,这没毛病。
如果我想只插入班级名,后两列都不插可以嘛

当然不行,报错说class_room这一列没有默认值,因为默认为空,但我们指定了这一列不允许为空,所以就没有默认值了.
如果我显式地给他插入一个NULL,当然也不行

因为我们约束了它不允许为空,这就是非空约束

2. 默认值(default约束)

默认值:

当我们在向表中插入数据时,如果某一列我们没有插入,则他会填充默认值。
就有点类似C++中的缺省参数,如果我们自己传了,那就使用我们传的参数,如果没传,那就使用缺省参数。
如果某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,将其作为默认值,在需要真实数据的时候,用户可以选择性的使用默认值。
比如有一个程序员的交流网站,用户注册时,性别这一栏就可以将默认值设为男,如果用户自己输入了,那就以用户输入的为准,如果没有,那就默认性别为男。

下面我们通过案例来理解一下:

建个表
create table t11( name varchar(20) not null, age tinyint unsigned default 18, gender char(1) default '男' );

第一列name,类型为变长字符串,长度20,同时我们约束不能为空(一定要插入非空值);第二列age,类型为tinyint,我们约束了默认值为18;第三列gender,类型为长度为1的定长字符串,约束默认值为男。
插入一些数据观察一下

我们发现,对于指定了默认值的列,如果我们自己插入了数据,就用我们自己插入的,如果我们没有自己插入,则用默认值。

3. 非空约束与default约束对比

再来看这样一张表:


与上面表t11的唯一区别就是gender这一列我们指定了默认值为男,同时还约束了非空。

那大家想,指定了默认值之后,如果我们自己插入数据了,那就用插入的,如果没有也有默认值,所以按理说就不会为空了。那not null是不是有没有都一样啊?

我们来验证一下:

先来关注一下第一列

这两条插入语句都不行,来分析一下:
第一条插入,我们给name列插入了空,但是建表时约束了not null,所以不能为空(报错也是这样说的)
第二条插入,我们没有给name列插入数据,报错说name列没有默认值。此时起作用的约束不是空属性,而是默认值约束。

再来观察第二列:

第二列设置了默认值,但没有约束非空,所以第一次我们不给第二列插入值,用了默认值18;第二次,我们插入了null,发现可以插入,因为并没有约束非空。
再观察第三列(即约束了非空,又指定了默认值):

第一次不插入用了默认值男,第二次插入空失败,因为约束了非空。

所以,回答上面的问题,第三列即设定了默认值,又指明了非空,那not null是不是有没有都一样呢?

显然答案不是的。
上面我们说:【指定了默认值之后,如果我们自己插入数据了,那就用插入的,如果没有也有默认值,所以按理说就不会为空了,那not null是不是有没有都一样啊?】
但是我们如果没有not null,我们还可以自己插入空,如果有,则不能插入空。

所以:

not null 和 default 并不冲突,而是互相补充的。
not null的约束什么时候起作用呢?
是当用户自己显式插入数据的时候 ,插入的值只可能是空/非空的合法数据,但若进行了非空约束,则不能插入null。
default呢?
用户忽略这一列的时候 ,此时如果设置了默认值,则自动填充默认值,如果没有设置,直接报错(即没有默认值的时候不能省略)。
不过实际应用中not null和defalut一般不需要同时出现。

下面再来做一个实验:

再建个表

有两列,name和age,类型和上面是一样的,不过这次我们没有添加任何显式的约束,非空和默认值
然后我们来插入一些数据

我们发现,插入空是可以的,因为没有非空约束;
而且任意一列插入的时候也可以省略,但是我们并没有指定默认值啊(其实我们之前就这样做过)。
不过我们看到可以省略,省略的话默认填充了null。
什么原因呢?

如图所示,原因在于,建表时如果我们自己没有手动指明默认值,MySQL会自动加上DEFAULT NULL,指明其默认值为null。
那如果我建表时只加了not null约束,没有加默认值,MySQL还会自动加DEFAULT NULL嘛?
就不会了,我们上面其实已经有对应的例子验证过了。

那没有默认值,用户就一定要自己插入值,又因为有非空约束,所以一定要插入非空值,这时not null约束就起作用了。

补充1: 列描述(comment)

列描述:comment,其实没有什么约束的作用 (严格意义来说COMMENT不是一种约束),没有实际含义,专门用来描述字段(类似编程语言中的注释),会根据表创建语句保存,用来给程序员或DBA(数据库管理员)来进行了解

下面我们还是通过案例来理解一下它:

建表


三列,这次每列我都添加了comment,描述了这一列的含义。
但我们看到它在desc 查看表结构里面并没有体现
通过show create table 表名;可以看到

所以它不是给数据库看到,用来给程序员或DBA(数据库管理员)来了解相关信息的,如果通过列名不知道这一列存的是什么,可以通过comment来了解。

补充2:zerofill(0填充)

zerofill在某些资料中也不被认为是一种严格意义上的约束,很多地方说法不一:

ZEROFILL 是 MySQL 中数值数据类型(INT、DECIMAL 等)的显示修饰符

下面还是通过例子来理解:

建个表

我当前的MySQL版本是8.0.44。
如果在版本更低一点的MySQL中,你可能看到的是这样的

建表的语句,出了表名完全一样,但是我们看到int后面有个(10)
int不是4字节嘛,那这个(10)是什么意思呢?
这里的(10)表示显示宽度
虽然我当前版本的MySQL没显示,但默认显示宽度仍然是 10。只是 MySQL 8.0 进行了显示优化。
我们先来给表中插入一些数据

没有问题。
然后我们来修改一下表结构,b这一列添加上zerofill属性
alter table t15 modify b int unsigned zerofill not null;

首先,我们观察到,我给b这一列添加了zerofill之后,(10)自动显示出来了。
然后我们再来查看表中的数据

我们发现b这一列,我们之前插入的2,它的前面多了9个0
那现在总的长度就是10 了,这跟括号里面的数字是匹配的。
那再插入一组数据

200本身长度是3,所以这次前面补了7个0,总长度为10。

这就是zerofill的作用:

如果插入数据的宽度小于对应的显示宽度(不指明默认为10),则会自动填充0。这样最后这一列的所有数据显示出来就是等宽的,即使我们插入的数据长度不一。
但是要注意,这只是最后显示的结果,在MySQL中实际存储的还是2和200。
我们可以来验证一下
方法一:

方法二:

16进制,对应的就是2和200。
可以看出数据库内部存储的还是2和200,补0只是设置了zerofill属性后的一种格式化输出而已。

当然这里默认显示宽度是10,我们也可以自己指定

比如改成5

那如果我们插入数据的宽度大于这个显示长度呢?


那是什么就显示什么,也不会给你截短。

最后,再来讲一个细节:

通过上面的例子我们知道这个默认显示宽度是10 ,而上面我们列的类型是int unsigned (无符号整形),那为什么是10呢?

因为无符号整形的最大值刚好10位。
如果类型改成int(有符号)

你会发现默认宽度变成11了,为什么多1?
int的取值范围是-2147483648 到 2147483647。
所以多的1是因为负数的时候,要显示负号。

相关推荐
倔强的石头_11 小时前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
阿巴斯甜16 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker17 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952718 小时前
Andorid Google 登录接入文档
android
黄林晴19 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android