初识mysql数据库之表的约束

目录

一、表的约束的概念

二、非空约束(空属性)

2. 空属性的使用

三、default约束(默认值)

1. 默认值的含义

2. 默认值的使用

 3. 默认值与非空约束的关系

3.1 默认值与非空约束的生效问题

3.2 default自动生成与not null的关系

四、列描述

1. 列描述的概念

2. 列描述的使用

五、zerofill

六、主键

1. 主键的概念

2. 主键的使用

3. 主键的丢弃

4. 主键的添加

5. 复合主键

6. 复合主键的使用

七、自增长

1. 自增长的概念

2. 自增长的使用

3. 自增长的实现原因

八、唯一值

1. 唯一值的概念

2. 唯一值的使用

3. 唯一值和主键的关系

九、外键

1. 表与表的关系

2. 外键的作用

3. 外键的使用

4. 外键命名


一、表的约束的概念

表的约束,简单来讲就是mysql为了防止用户输入非法数据而对用户的一些限制。如果表不对用户输入进行限制,就可能出现用户在性别栏填手机号,在手机号填性别这类不合法的数据。因此,表中一定要有各种约束,通过约束,让用户在未来插入数据库的表中的数据是符合预期的。

其实,在之前的文章中介绍数据类型的时候,讲过在float后面的括号中是数据的长度和小数点的位数,在char后面的括号中是字符长度,同时每个数据类型里面要填的值都是有要求的,这些就是表的约束。

约束本质是通过技术手段,倒逼程序员插入正确的数据。反过来说,只要是插入数据库中的数据,一定都是符合数据库的约束的,即保证数据的完整性和可预期性

真正约束字段的是数据类型,但是数据类型约束很单一,无法满足需求。此时就需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。

表的约束有很多,这里不会一一介绍,而是选择几个比较常用的介绍。即表的属性中后面的NULL等属性的作用。

二、非空约束(空属性)

null想必大家都不陌生了,在C++中,null无论是在字符上还是在数字上,它表示的含义都是0。但是在mysql中,null的含义就和C++中不太一样了。

在表的属性中,有一个空属性,这个空属性中有两个值,分别是null(默认的)not null(不为空)

它的含义就是“是否允许某一列为空”。如果是null,表示允许该列为空;如果是not null,则不允许该列为空。

这就好比我们在填一些调查问卷的时候,有些题是必做的,它可能就会用*标识出来,这些题的答案其实就是数据库中必须要的,为not null;而有些题则不是必须做的,即数据库对这些数据可要可不要,即null。 

2. 空属性的使用

为了方便演示,这里创建一个简单的班级表,这个表中有班级和教室两个不能为空的信息和一个other,可以为空的信息。

创建如下一个myclass表:

查看它的详细属性:

可以看到,在属性栏中,null一栏中class_name和class_room都是NO,而other则是YES。意思就是class_name和class_room是不允许为空的,而other则允许为空。

首先先向这个表中的三列都插入数据:

三个全部插入是没有问题的。

再测试只插入前两列:

同样可以正常插入。

再来测试只插入第一列:

此时就无法插入了。因为class_room列是not null的,不允许为空。

既然无法省略,那我们能不能向里面插入null呢?

可以看到,此时就报错说不能为空。这也就验证了上文中说的,为not null属性的列是不允许为空的。这就叫做“非空约束”。

注意,数据库默认字段基本都是字段为空,但是实际开发时,因为数据为空是不会参与运算的,所以大家最好尽可能保持字段不为空

三、default约束(默认值)

1. 默认值的含义

默认值,即某一种数据会经常性的出现某个具体的值,这种值就可以在一开始就指定好,在需要真实数据的时候,用户就可以选择性的使用默认值。这个默认值大家可以理解为C++中在类中使用的缺省值,两者的作用都是差不多的。

默认值的生效条件也会C++中的缺省值一样,数据在插入时不给指定了默认值的字段赋值,就会使用默认值

举个例子,假设现在有一个表,表中有一项数据是性别,程序员对这个字段指定了默认值为“男”。如果用户输入了性别,表中就使用用户输入的性别;如果用户没有输入性别,表中就填默认值“男”。

2. 默认值的使用

要使用默认值很简单,在创建表时在对应字段的后面带上“default 指定值”即可。为了方便演示,先创建如下一个t1表:

在这个表中,就为age和sex指定了默认值。查看这个表的详细属性:

可以看到,在详细属性中的default列中,name是null,age和sex则是我们创建表时填入的默认值。

为了看到结果,我们分别插入两条数据,分别是指定了age、sex和没有指定age、sex的。

插入完后查看表中的值:

表中的数据就分别是我们自己填的值和默认值,印证了上文说的在有默认值时,如果用户填了值就使用用户的值,如果没有则使用默认值的说法。

 3. 默认值与非空约束的关系

3.1 默认值与非空约束的生效问题

从上文中可知,当一列被设置为not null时,这一列在插入的时候就必须要有值。但是默认值可以在用户不填入值时默认使用。既然如此,那默认值和非空约束之间有什么关系呢,是否会互相影响呢?

创建如下一个t2表进行测试:

注意,在这个表中,我们特意给gender赋予了not null属性和设置默认值。这两个属性是可以同时有的,并不冲突。

查看它的详细属性:

属性和我们的预期一样。因为name和gender都设置not null,而age没有设置,所以它的NULL一栏是NO/YES/NO。而default一栏也和我们写的一样。

因为name一栏设置了not null,所以我们向里面插入一个null试试:

此时它的报错为name不能为null。

再试试不向name插入值:

可以发现,此时的报错和上面插入null就不同,这里的报错是没有默认值。

通过这两个实例就可以得出一个结论,当我们不填值时,并不是由NULL属性来判断是否拦截,而是用是否有default来判断是否拦截。这就是说,我们在插入一个设置为not null属性的列时,如果我们没有指定要插入某个值而是使用默认值,如果对应列中没有设置default值,就无法插入。

换句话说,我们在对一个设置为not null属性的列插入时,如果我们不指定值而是使用默认值,只要这个默认值存在,就可以插入。到底是不是这样呢?注意,在建表时,我们特意将gender赋予了not null属性,并添加了默认值。因此我们可以gender来测试:

可以发现,此时数据正常插入,并且从表中的数据可以发现,gender就是使用的我们创建表时给gender填的默认值。

由此我们可以得出一个结论:默认值和not null并不冲突,而是互相补充的。当用户主动插入数据时,只能从null和合法数据中选择。而null则被not null拦截,使得用户只能填合法数据。

默认值则是在用户不想主动插入数据数据时生效,如果对应列有默认值,则使用默认值;如果没有默认值,直接报错

3.2 default自动生成与not null的关系

现在又有一个问题,如果我们既不填not null也不指定default,此时如果不向对应列插入值,会是什么现象呢?创建如下一个t3表测试:

向这个表中插入如下数据:

从结果可以看到,虽然name一栏并没有插入数据,但依然可以成功插入。并且表中的name栏甚至填上了null。可是从上面的创建表来看,我们并没有给name添加默认值啊,那为什么这里会添加null呢?

查看创建t3表时的创建指令:

可以发现,mysql中保存的创建指令中虽然我们没有填默认值,但是它自动带上了default null,即设置默认值为null

再来看上面的t2的创建代码:

可以发现,在t2中,由于我们给name设置了not null属性,它的后面就没有自动带上default null。

原因很简单,not null的含义是不允许插入null,而default如果不设置就默认为null,此时就会产生冲突。所以如果某列中设置了not null但没有设置default,mysql就不会自动添加default null。 

因此,not null和default一般不需要同时出现,因为default本身就有默认值,不会为空。当然,同时出现也并没有什么问题。

四、列描述

1. 列描述的概念

列描述是使用comment,这个字段没有实际含义,只是用来标识后面的内容是用来描述字段的。它会根随表创建语句被保存起来,用来给程序员或DBA了解数据库。

简单来讲,列描述大家可以看成C++中的注释。 

2. 列描述的使用

创建如下一张t4表:

表中圈起来的部分就是列描述。

查看它的详细属性:

可以发现,表的属性并没有因为列描述而产生什么变化。

再查看表的创建指令:

可以看到,在表的创建指令中就有了我们刚刚写的列描述。列描述的作用就是在这里显示,让程序员更好的理解数据库中的各项内容。

既然列描述不会对数据库的数据构成影响,那我们怎么理解它是一种约束呢?列约束只是一种软约束,这些信息是给程序员看的,让程序员知道每一列中的内容应该是什么

五、zerofill

如果大家看了我的上一篇文章中的数据类型,大家应该知道,在整数类型中,并没有介绍它后面带的空格是什么意思。以int为例,创建如下一个t5表:

查看它的详细属性:

可以看到,虽然我们在创建表是并没有在int后面添加(10),但是mysql还是自动带上了。那这个括号中的内容到底是什么呢?

向里面添加一个值,先向里面添加如下数据:

显示的结果符合我们的预期。然后我们再修改一下b的属性,给它添加zerofill属性

添加完后,再查看它的详细属性,可以发现,在type栏里b的后面就多了个zerofill。那这个字段有什么用呢?再次查看表内容:

可以发现,显示2的时候,2的前面就多了一串0。再添加如下数据:

可以发现,此时在200的前面也是有0来填充的。如果大家仔细观察一下就可以发现,通过0填充后的数字,它的位数刚好是10,和我们在上文中看到了int(10)是一样的。

既然如此,我们修改一下int后面的括号里面的值,看一下是不是会会自动填充0以显示特定位数。

修改成功后,输入以下数据进行测试:

查看表中的数据:

可以发现,当b中的数据的位数小于4时,会自动填0以补充为4位,但如果超过4位,则什么都不会做。这也就是说,zerofill的作用就是在数据的宽度小于设定宽度的时候,自动填充0

上面的表中的两个值都是int unsigned的,再看一下int是什么样的:

可以看到,当时符号int时,括号内的值是11;当时无符号int时,括号内的值是10。原因很简单,我们知道,无论是有符号int还是无符号int,它们的取值范围最大也就是十亿级别的。而十亿级别表现为位数时,也就10位而已。因此,为了表现最大位数,无符号int就被设置为了10;而有符号int中多出来的一位则是符号位,用于表明正负。

注意,虽然显示的时候是全部补0的,但是在实际的存储中不会存储这些0的,而是存储未填充0的值。补0只是一种格式化显示手段

由此可知,整数类型后面的括号中的值就是用于在有zerofill属性时填0格式化显示的,并没有其他作用。这也就意味着,如果整数类型没有zerofill属性,那么它后面的括号中的值没有任何意义。

六、主键

1. 主键的概念

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

那为什么要有主键呢?其实很简单,因为在某些情况下,我们希望表中的某些数据是不能重复的。例如大家在学校里面的学号,学校用学号来标识唯一一个学生,学号就不能够是重复的。

2. 主键的使用

创建如下一个test_key表:

查看它的详细属性:

可以看到,当设置了primary key后,在表的key栏中,id的属性就多了一个PRI,这就表明id被设置了主键。同时可以发现,id的NULL栏是NO,即not null属性。这也就印证上文中说的设置了主键的列不能为空的说法。

表创建好后,我们先插入一个数据:

可以正常插入。然后再插入一个相同的id和不同的id进行测试:

可以看到,当插入相同的id的时候,mysql就报错说1重复了。但是换成了一个不重复的id时,就可以插入了。

3. 主键的丢弃

在上文中,我们在创建表时就设置了主键。那如果我们突然不想要这个主键了呢?很简单,执行“alter table 表名 drop primary key”即可:

此时表的属性内就没有PRI字段了,即不再有主键。有人可能会疑惑,主键明明是id的属性,为什么丢弃主键的时候可以不操作id直接丢弃呢?其实是因为一个表中只有一个主键,所以无需指定列就可以让mysql自行找到主键然后丢弃。

当主键被丢弃后,就可以插入有重复id的值了:

4. 主键的添加

现在我们的test_key表中已经没有主键了,那如果我们现在又想给id添加主键呢?很简单,执行“alter table 表名 add primary key(列名)”

 当我们添加主键时,mysql却报错说表中的2重复了。查看表的内容:

确实id为2的有两个。此时由于id重复,就无法添加主键了。如果想添加主键,就需要让id不再重复。因此,我们就删除掉一个数据,让2不再重复:

当删除掉一个重复数据后,就可以向表中添加主键了。

通过这个实例,大家就应该要知道,要添加主键,最好就是在创建表的时候添加,再不济也要在向这个表插入数据之前添加主键,以避免出现要添加主键的列中有重复情况而导致主键添加失败。 

5. 复合主键

上文中我们说,一个表中只能有一个主键,但是这并不代表一个主键只能用于一列。也就是说,在同一个表中,可以给多列添加主键的。而这种用于多列的主键,就叫做“复合主键”

6. 复合主键的使用

创建如下一个带有复合主键的pick_course表:

此时就创建了一个带有复合主键的表,其中主键用于id和course_id,表示id和course_id都不能重复。

查看它的详细属性:

虽然它的属性里面id和course_id都带有PRI,表示使用了主键,但是它们使用的是同一个主键。

那么这两列在使用主键后,究竟是表示这两列的值不能同时重复,还是表示其中有一个重复都不行呢?插入如下数据进行测试:

通过上面的测试可以发现,当course_id重复,但id没有重复的时候,是可以正常插入的。然后我们再来尝试一下让这两列同时重复看能否插入:

当两列都重复的时候,就出现了报错,并且从报错中可以发现,是“2-40”出现了重复。这也就是说,当同一个表中不同列使用同一个主键时,mysql是将这些列视为一个整体,当这些列同时重复的时候才会报错;如果有一个不重复,就不会报错。 

七、自增长

1. 自增长的概念

自增长,即auto_increment,当对应的字段没有给值的时候,mysql会自动将当前字段中已经有的最大值+1后填入对应列。自增长一般和主键单配使用,称为逻辑主键

自增长的特点:

1. 任何一个字段要做自增长,前期是本事就是一个索引(key栏有值)。

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

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

2. 自增长的使用

创建如下一个t6表:

查看它的详细属性:

可以看到,在设置了auto_increment属性的列中的extra栏,就有了auto_increment字样。那这个属性有什么用呢?插入如下数据测试:

可以看到,我们在插入数据时并没有插入id的值,但是显示的结果中却是从1开始向后填。这也就是说,自增长的作用就是可以让某列自己在不重复的情况下向上增长值

那如果我们此时自己插入一个id,这个值会如何变化呢?插入如下数据进行测试:

可以看到,当用户自己插入一个新的值后,自增长的值就是在这个新值的基础上增加。

通过上面的两个例子,就可以得出如下结论:带有auto_increment属性的列,如果用户没有填值,就默认从1开始向上增长;如果用户填入了值,就默认从用户填的值开始向上增长

在上文中说了,自增长必须是整数,我们给一个不是整数的值设置自增长:

此时就报错了,说不能给那么设置自增长。至于其他两个错误就不再验证了,很容易理解。

3. 自增长的实现原因

既然自增长可以自行增长,那它是如何做到的呢?查看这个表的创建信息:

可以看到,在创建信息中,这个表的表外被mysql自动添加上了一个字段,这个字段中的内容就是当前表的最大id + 1

既然mysql在表外会自动帮我们添加这个字段,那我们可不可以自行添加然后设置起始值呢?先创建如下一个t8表:

在这个表中,就指定了自增长值从500开始。插入数据进行测试:

可以看到,确实是从500开始插入。这也就说明我们确实可以在表外定义自增长的起始值

八、唯一值

1. 唯一值的概念

要理解唯一值,我们首要要知道主键的缺点。上文中说了,在一张表中只能有一个主键,带有主键属性的列里面的值不能重复。

但是主键有一个问题,就是不能支持让多列的数据都不重复。虽然一个主键可以给多列用,但是只有当这些列同时重复的时候主键才会生效,如果这些列中有一个不重复,主键都不会生效。因此,如果遇到我们需要不同的列都不重复,例如一个学生的id和身份证号,我们在插入数据时想让这两列中的值都不重复,此时主键就无法满足需求了。

因此,一张表中往往有很多字段需要唯一性,保证数据不能重复。但是一张表中只能有一个主键,无法满足需求。而唯一值就可以解决表中有多个字段需要唯一性约束的问题。这也就意味着,一张表中可以存在多个唯一值。

2. 唯一值的使用

先创建如下一个stu表:

对应列后面带上unique字段,就表明添加唯一值属性。查看它的详细属性:

在这里我们可以发现,key栏中多了UNI字段,该字段就表明对应列有唯一值属性。同时还可以发现,添加了唯一值属性的列的null栏为YES,就说明这列是可以为空的。这一点就和primary key在添加后会自动添加not null属性不同。

创建好表后就以插入如下数据:

可以看到,确实可以插入。大家应该知道,null是不参与计算的,因此,我们再来测试一下能否继续插入null:

可以看到,在带有唯一值的列为null时,确实可以重复插入

再来看一下正常情况的插入:

此时就无法插入了,符合预期。

通过上面的例子,就可以得到一个结论:唯一键允许为空,而且允许重复的空值,空字段不做唯一性比较

上文中说过,在一个表中可以存在多个唯一值,因此我们创建如下一个student表来测试:

在整个表中就存在多个唯一值和一个主键。查看它的详细属性:

key栏中也正确显示了对应的主键和唯一值。

先向里面插入如下一个数据:

插入完成后,逐个测试一下主键和唯一值:

可以发现,逐个测试过去时,mysql就分别将id、telphone和qq三个不能重复的值检测出来了。

通过这种方式,就可以保证插入表中的值是不重复的了。当然,仅仅只能保证数据不重复,但不能保证用户插入不重复的错误的数据时可以被检测出来。

3. 唯一值和主键的关系

唯一值和主键都可以用来保证某列的值是不重复的。对于主键,大家可以简单理解为从众多唯一值中选出一个值充当主键。 是用来补充主键的不足的。

选择唯一值和主键时,一般建议将主键设计成和当前业务无关的字段,当出现业务调整时,就可以尽量不对主键做调整

九、外键

1. 表与表的关系

在上面的所有内容中,我们讲的都是一个表内的约束。但是要知道,表与表之间也可能是有关系,需要约束的。

例如一个学校里的学生,它有非常多的信息,如学号,姓名、年龄、入学时间、年级、班级等等信息。如果将这些信息全部放在一起,势必会导致这张表非常的冗杂,不好看。因此,我们此时就可以尝试将不同信息进行归类,放在不同的表中。例如准备一个班级表,专门存放有哪些班级;再准备一个学生表,里面就是学生的各类信息,班级栏就直接填班级表中对应的数字:

通过这种方式,就让表看起来很简洁。在这两个表中,学生表的班级栏依靠班级表中的编号,因此,此时学生表就叫做从表,班级表就叫做主表班级id就叫做“外键”。当然,这个外键当前还不完整。

为了方便测试,首先创建如下一个student表:

然后再创建如下一个class表:

当着两个表创建好后,再向班级表中插入两个班级:

班级表插入的完成后,再向学生表中插入数据:

在这里面就成功插入了学生的数据。如果我们想知道class_id栏中的值代表什么意思,直接查询班级表中的值即可:

这样看,似乎没有什么问题。但是,如果我们插入一个class_id为3的学生呢?

可以看到,依然可以正常插入。但是按照道理来说这张学生表里面应该不可以插入这个数据才对,因为class表中根本没有id为3的班级。因此,此时这份数据就是一份错误数据,但依然可以插入。

如果我们愿意,甚至可以将class表中的某个班级删掉:

此时class表中的id为1的班级就被删除了。但按照常理来讲,class表中id为1的班级不应该可以被删掉才对,因为student表中还有学生的class_id为1,此时这些学生就找不到对应的班级了

究其原因,就是在这两个表中的外键,徒有外键之名,而无外键之实。外键的构成应该由“关联”和“约束”两部分构成,但在上面的例子中,仅仅只有关联,却无约束。由此,这两个表中可以不顾对方的情况随意插入合法的数据。

2. 外键的作用

通过上面的实例,我们就可以得出外键的作用——外键用于定义主表和从表之间的关系

外键在使用时,外键约束主要定义在从表上主表则必须是有主键约束或unique约束当定义外键后,要求从表中有外键属性的列的数据必须在主表的主键/unique列存在或为null

外键定义方法很简单,如下图所示:

3. 外键的使用

有了外键的知识后,就可以重新创建一个定义了外键的student表了:

在这个表中就将class_id添加了外键属性,并与class表中的id相关联起来。

查看它的详细属性:

在class_id栏就有MUL字段,表示外键。

重新向class表中添加编号为1的班级:

准备工作做好后,就可以插入数据了。先插入班级为1和2的数据:

此时可以正常插入。

再向里面插入一个不存在的班级编号:

此时mysql就报错了,说外键约束失败。简而言之就是class表中的id列没有对应值。

既然无法向student表中插入class表中不存在的id,那我们来尝试一下能否删除class表中的班级:

删除失败。原因就是student表中还有班级编号为1的数据,所以class表无法删除。

当然,如果student表中没有class_id为1的学生,那就可以可以正常删除class表的id为1的班级了。

4. 外键命名

外键在使用时是可以取名字的。查看上面的student表的创建信息:

可以看到,在创建信息中,有个constraint字段,后面跟着一个名字,这其实就是这个外键的名字。所以如果你愿意,也是可以在这里给外键去名字的,但是没什么必要,这里只是简单介绍一下。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值