MySQL数据库(5)—— 表的约束
目录
一,前言
二,基础约束
2.1 空属性
2.2 默认值
3.3 列描述
4.4 zerofill
三,键约束
3.1 主键
3.2 复合主键
3.3 自增长
3.4 唯一键
四,外键
4.1 问题发现
4.2 外键约束
一,前言
- 约束主要设针对数据类型,如果插入的数据超出了对应数据类型的取值范围,那么数据将会插入失败
- 表中一定要有各种约束,有了约束,就能让我们未来插入到数据库的表中的数据是符合预期的,所以约束的本质就是通过技术手段,倒逼程序员插入正确的数据。
- 反过来,站在MySQL的视角,凡是插入进来的数据都是符合数据约束的,也一定程度上增加了MySQL内部逻辑的正确性
- 总结:约束的最终目标,就是保证数据的完整性,正确性和可预期性
二,基础约束
2.1 空属性
空属性有两个值,分别是null和not null,数据库默认字段基本都是允许为空的,但在实际开发中我们要尽可能保证字段不为空,因为空值无法参与运算,如下:
在建表时,我们要让某个字段不能为空,那么就要在后面加上not null属性:
这样在后面插入值的时候,必须填上插入这个位置的值,不然就会报错,如下:
问题:NULL和 '' 有什么区别?
解答:
- 我们上面插入三个值,非空的other字段我们一个没插入值,一个只写了单引号但是里面没东西
- NULL和 '' 不一样,后者表示一个字符串,但是这个字符串是空的,没有任何字符;前者才是真正的什么都没有
- 为了方便理解,我们可以用string做例子,我们创建了一个string但是还没有往里面插入数据,但是我们创建的string里面有很多类方法和类成员变量,所以string里面还是有东西的,而NULL就是真的什么都没有
2.2 默认值
- 可以理解为初始值,C++中叫做“缺省值”,虽然叫法不同但是本质是一样的,就是给一个字段设置一个默认值,在向表中插入数据时如果没有给该字段赋值,那么该字段就会自动用默认值填充
- 一旦给某字段设置了默认值,那么该字段就不会再出现NULL了
- 并且如果一个字段设置了default,那么再设置not null也没有任何意义了
3.3 列描述
- 换个说法,就是“注释”,在创建表时用来对各个字段进行描述
问题:如何理解comment也是一种约束?
解答:上面说过约束的最终目标就是保证数据的完整性,正确性和可预期性,数据不仅仅由用户提供,也由程序员维护,所以在约束用户的同时,也会给程序员约束,所以comment是给程序员看的,是一种软件层面的约束
4.4 zerofill
- 这个东西也可以认为是一种默认值,default是针对字段的,zerofill是针对类型的
- 以varchar(20)为例,数值类型后面的括号中的数字代表宽度,如果对应数值设置zerofill属性后,如果数据的宽度小于设定的宽度,则自动填充0
下面是没有设置zerofill的演示:
下面是添加zerofill的演示:
但是需要注意的是,zerofill只是在显示层面填充了0,并没有影响其真正存储的值:
最后需要注意的是,添加0的数量是和数值类型后面括号里的值来定的,如果是int(5),那么就会填充4个0,int类型默认是int(10),如上图,所以填充9个0
问题:为什么int默认为10?
解答:整数大小为-2^31 ~ 2^31-1,无符号整数位0 ~ 2^31-1,分别换算下来就是42亿和21亿多,这么大的数字表示起来其实也就是10位数
三,键约束
3.1 主键
①为什么要有个主键?
- 当一个表里的数据非常非常多时,查询起来就比较困难
- 这时候可以讲某一字段作为主键key,当需要查找记录时就可以根据这个主键来查找对应的记录,能大大减少查询的时间
②主键的规则
- 首先,主键最多只能有一个,也就是说在建表时只能给一条字段设置primary key标记为主键,有两个时就会报错
- 主键默认是not null的,也就是不能为空,并且主键不能重复,比如学生id,规则上一个学校是不允许有重复学号的
③演示
首先是设置主键:
主键不允许重复:
可以通过主键来查询信息:
也可以通过主键来更新或删除内容:
主键也可以删除和添加,但是前提是主键的数据不能重复,如果是在建表后添加主键,如果这一列数据有重复就会添加失败,所以建议是在建表时加上主键:
3.2 复合主键
- 前面说过一个表只能由一个主键,但是并不意味着主键只能添加给一列
- 一个主键可以被添加到多列上,这种添加到多列数据上的主键我们称为“复合主键”
- 而且这多个添加了主键的列都要遵守主键的规则,但是只有当这些列都违反规则时才会报错,具体看下面演示
首先是建立复合主键:
在向进程表插入数据时,只有插入进程的IP和端口都出现冲突时才会产生复合主键冲突,否则正常插入:
复合主键和主键一样可以删除和添加,就是添加的时候,要在后面的括号里填入多个列即可
alter table 表名 drop primary key;
alter table 表名 add primary key(多个列名);
3.3 自增长
- 设置了自增长的字段,插入数据时如果没有给该字段赋值,那么系统会自动找出当前列已有数据中的最大值,将该最大值加1后插入该字段
- 任何一个字段要做自增长,前提是本身必须是一个索引(就是key那一栏有值,目前可以认为主键就是一个索引),并且自增长字段必须是数值类型,一张表最多只能有一个自增长字段
- 自增长通常和主键搭配使用,但是一般而言,建议将主键设计成与当前业务无关的字段,避免因为业务逻辑的调整而需要修改主键,下面是演示:
①添加自增长属性
②如果插入的第一条记录时没有指明,会自动从1开始,并且后续插入仍然没有指明时,会依次递增:
③如果指明了,那么下一次插入会从本次指明的数字开始,前提时指明的数字不能和已有的数字重复:
3.4 唯一键
- 主键虽然能解决一条字段的唯一性,但是一张表可能有很多字段需要唯一性,但是主键只能有一个
- 所以有了唯一键,它可以有多个,负责一张表中多个字段的唯一性
- 唯一键和主键都能保证字段中数据的唯一性,但是唯一键允许为空,并且也允许多个字段同时为空,因为空字段不做唯一性比较
- 可以理解为主键是特殊的唯一键
①首先是添加唯一键
②当插入的数据的唯一键字段和已有字段重复时,插入会报错
③如果插入时不指定唯一键字段的值,那么会默认插入NULL
问题:主键和唯一键不会冲突吗?
解答:
- 人身上是有很多的属性值的,建表的本质其实就是通过表来描述对应的一个对象,mysql上的每一个表相当于C中的结构体,C++里的类,用来描述一个具体的事物。
- 我们选择或设置主键通常有两种做法:一种是从我身上众多具有唯一属性的列,选择出某一列称为主键;另一种是选择一个和业务无关的列作为主键
- 所以一个人身上某个唯一属性没有被选为主键,但不代表这些没有被选为主键的属性没有唯一性,也需要维护唯一性,所以主键和唯一键不冲突。
四,外键
外键这个东西比较复杂,我们单独分一个标题来讲解
4.1 问题发现
我们先搞两个表:
学生表:
班级表:
先往表中插入一些值:SQL如下:
insert into class values (1,'计算机101');
insert into class values (2,'计算机102');
insert into student (name,telphone,classid) values ('张三','123456789',1);
insert into student (name,telphone,classid) values ('李四','123456798',3);
insert into student (name,telphone,classid) values ('王五','123456987',2);
insert into student (name,telphone,classid) values ('赵六','123459213',3);
假设上面是我粗心,把部分同学的班级都输入成了3班,可以插入,但是我们的班级表中只有1班和2班,所以上面的SQL可以插入,但是在逻辑上是错误的
所以我们发现了问题所在,所以我们要想办法避免上述情况,当然是要在技术上避免
4.2 外键约束
①我们先建立外键
②上面就是将学生表的classid和班级表的id挂钩,当插入值得classid在班级表里有的时候才能允许插入,没有则会报错,这就是外键约束