MySQL基础 [四] - 表的约束

目录

​前言

空属性null && not null

默认值default

列描述(描述字段  软约束)

zerofill(格式化显示  软约束)

主键约束

auto_increment(自增长+搭配主键+允许表外设置)

唯一键

外键

综合案例的练习


​前言

表中一定要有各种约束,通过约束让我们在未来使用数据库的时候,操作的结果都能是符合预期的!约束的本质就是通过技术手段倒闭程序员插入正确的数据!

​ 真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,这是为了更好地 保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是 email,我们要求其是唯一的,不能说要填啥就填啥,所以就要约束!

​ 表的约束很多,这里主要介绍如下几个:null/not null、default、comment、zerofill、primarykey、auto_increment、unique key。

空属性null && not null

  • 一共就是两个值:
    • null:表示该项可以为空(默认选项)
    • not null:表示该项不能为空
  • 数据库默认字段基本都是字段为空,但是 实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。
  • null 是不区分大小写的,并且这和编程语言中的 null 不一样。

比如我们在网上填写一些登录注册信息的时候,会看到网页或者客户端提示哪个字段必填,这也是因为该字段是必须要录到数据库中的,不能为空!

下面我们写个案例:

创建一个班级表,包含班级名和班级所在的教室。站在正常的业务逻辑中:

  • 如果班级没有名字,你不知道你在哪个班级。
  • 如果教室名字可以为空,就不知道在哪上课。

所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是约束!

默认值default

在 mysql 中,可以为表中的列指定默认值。默认值是在插入新行时自动分配给该列的值。如果插入语句中没有为该列提供值,则将使用默认值。

​ 要为列指定默认值,可以在创建表时 使用 default 关键字,或者在已存在的表上使用 alter table 语句。

​ 下面直接举例子,这里我们还要和上面学的空属性进行对比:

下面我们试着插入几组数据,试着省去其中的参数:

 为了更好的体现空属性和默认值的区别,我们下面再创建一个表:


既然属性设为不为空,也就说咱们一定要填值并且不能为 null,但是此刻 gender 又有了默认值,这不是暗示可以不填值吗,这不冲突吗❓❓❓

​ 其实并不冲突,上面的例子在不插入 name 字段的时候,会报错的原因,其实是因为 当我们不填值的时候,其实默认填的就是 null,此时因为和 name 中设置的 not null 冲突了,才会报了 doesn't have a default value 的错误!

​ 而我们这里给 gender 字段设置了 not null 和 default,实际上并不冲突,因为当我们不填的时候,会拿默认值去填,此时的默认值只要不是 null 就能成功,我们可以测试一下:

所以得出结论,default 和 not null 是互补的,而不是冲突的!
有人可能会问,不设置默认值的时候,默认插入 null,这可以证明吗?
​肯定是可以的呀!下面我们创建一个不带默认值的表,然后看看 mysql 做的小优化:

列描述(描述字段  软约束)

列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或 DBA(Database Administrator 数据库管理员)来进行了解。

注意:一般情况下不需要not null 和 default同时出现,因为default本身有默认值,不会为空

​要查看的话一般要通过 show create table table_name \G 来进行查看!

zerofill(格式化显示  软约束)

想必刚学数据库的时候,大伙都会对下图中红色框中的内容感到疑惑吧:

 要说 varchar(20) 类型后面跟着的数字是字符的长度还能理解,但是一个整数类型为啥也有长度,还是说这不是长度?

其实 整数类型后面的括号中的数字表示的是零填充的宽度!举个例子,如果是 int(4) 的话,表示零填充的宽度为 4,此时我们插入一个值为 300,它的长度是 3,小于零填充的宽度 4,所以当我们查询结果的时候,会看到返回的是 0300,也就是默认在前面填充 0 直到达到零填充的宽度为止!

​ 如果我们要看到这个显示效果的话,必须配合一个关键字属性 zerofill,不然是没有意义的!

​ 下面我们创建一个表来看看不同的宽度有什么效果:

 至于为什么 int 类型默认是 10,这是因为 int 的最大范围就是十位数!

主键约束

我们最好是在表创建的时候,或者是表创建了但是还没正式使用的时候就进行主键约束的,如果我们正式使用了再去主键约束,那么会很麻烦的,因为一旦有了相同的主键,我们在添加主键约束的时候就会报错,需要把重复的主键删了之后,才能进行主键约束。

复合主键:在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段作为主键, 可以使用复合主键。

primary key(id, course) -- id和course为复合主键 

我们不是刚刚说了,一个表最多只有一个主键吗?

有两个PRI不证明有两个主键,,它们两个合起来才算一个主键 

但是这样就不行了

当两个合起来之后,这两个数据跟表里的都不一样,可以插入有一个一样的,也可以插入但是当都一样了,此时就是主键约束,不能插入了 

auto_increment(自增长+搭配主键+允许表外设置)

如果我们没设置id的话,id会自动帮我们插入,然后自增。且保证不冲突, 一开始默认是1

如果我们新插入一个id,就会以我们新插入的为主

 在插入后获取上次插入的 AUTO_INCREMENT 的值(批量插入获取的是第一个值)

我怎么知道到底下一次该从哪一个数字开始自增呢??

刚才我们手动插入1000的时候,就自动的将AUTO_INCREMENT值给修改了

在auto_increment不仅可以在表内是设置,也是可以在表外被设置的,他会表示下次插入时的起始值。如果没设置就是从1开始

应用场景:qq账号,我们申请qq账号的时候用手机号申请他会通过后台给我们返回一个账号。 在数据库后台他是自增的。

一张表最多只能有一个自增长,且必须有主键

获取最后一次插入的值

select last_insert_id(); 

其实在使用的时候,自增长一般跟索引相结合,这里先简单介绍下,后续我们再详细的谈索引 

索引(类似目录,一种加速查找的策略    往往和主键有关系

 在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中 一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录, 可以根据目录中的页码快速找到所需的内容。

       索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息。 

       数据表很大的时候,利用一部分空间来存索引(内容和数据页码),加速我们对表数据的查找,达到空间换时间的目的 

唯一键

在 mysql 中,唯一键(Unique Key)是一种约束,用于 确保表中的某个列或一组列的值是唯一的,防止重复数据的插入或更新。在创建表时,可以通过在列定义中使用 unique 关键字来指定唯一键!

它和主键的唯一区别就是 如果该列字段没有设置 not null 的话,那么定义为唯一键的话是可以插入 null 值的,而 主键则不可以插入 null 值!

问题来了,不是已经有一个主键 primary key 了吗,为啥还需要一个唯一键,这不是多此一举吗?

其实并不会!并且 它们的关系其实是互补的!假设有以下场景:

​ 比如在公司,我们需要一个员工管理系统,系统中有一个员工表,员工表中有两列信息,一个身份证号码,一个是员工工号,我们可以选择身份号码作为主键。

​ 而我们设计员工工号的时候,需要一种约束:而所有的员工工号都不能重复。这具体指的是在公司的业务上不能重复,我们设计表的时候,需要这个约束,那么就可以将员工工号设计成为唯一键。

​ 所以一般而言,我们 建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对主键做过大的调整。

​ 而会 将与业务有关的并且不能重复的字段设计为唯一键!

下面来举个例子大家就懂了,我们创建一个表,其中 id 字段是作为主键,然后其它字段我们先不设置唯一键:

很明显就能看到问题,虽说我们创建了主键来标识每个用户,但是用户的手机号和qq号还是会出现重复的情况,这可能是因为在录入信息的时候的错误操作,但是 归根结底,是我们数据库的表设计的不好!

可以看到唯一键是可以插入空值的,代表该项信息是没有的,这是因为 唯一键的工作就是为了防止字段值重复而已! 

可能会有人问,那我们不是学了复合主键吗,为什么不用复合主键来代替唯一键呢? 

 这个问题不错,但是结合上面的例子再仔细一想就知道,我们日常生活中有很多与别人不重复的信息,但是有些别人有的信息,咱们不一定有,所以得有 null 的存在,但是复合主键的特点之一是不能为空,这就导致了和我们的意愿不符合的情况,所以必须要有唯一键!

外键

外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有 主键 约束或unique 约束。当定义外键后,要求外键列数据必须在主表的主键列或者唯一键列

foreign key (字段名) references 主表(列)

学生表叫做从表,班级表叫做主表,因为学生表要依附于班级表,他需要通过class_id和班级表产生关联,此时class_id就称作为外键  主表需要给其他从表提供可以和自身产生关联的外键约束(一般都是主键或者唯一键)

我们再建一个表 

foreign key (字段名) references 主表(列)

这时候就建立了外键约束,如果学生表插入了不存在的班级id,或者班级表删除了有关联学生的班级id,mysql都会拦截这种行为

 我们再去尝试先删除学生,再删除班级

此时就是可以删除班级了,因为这个是合法的行为,我允许你,但是非法的行为,我就限制约束你

外键总结:

1、从表和主表的关联关系

2、产生外键约束

目标:确保表和表之间的完整性比如有学生(从表)对应班级(主表),不会在学生表插入一个不存在班级,也不会在班级表删除一个还有学生的班级

综合案例的练习

有一个商店的数据,记录客户及购物情况,有以下三个表组成:

  • 商品goods (商品编号goods_id,商品名goods_name, 单价unitprice, 商品类别category, 供应商provider)
  • 客户customer (客户号customer_id,姓名name,住址address,邮箱email,性别sex,身份证card_id)
  • 购买purchase (购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums)

要求:

  • 每个表的主外键
  • 客户的姓名不能为空值
  • 邮箱不能重复
  • 客户的性别(男,女)
//创建数据库

create database if not exists mall default character set utf8 ;

//选择数据库

use mall;

//创建数据库表

//商品

create table if not exists goods (  

goods_id  int primary key auto_increment comment '商品编号',  

goods_name varchar(32) not null comment '商品名称',  

unitprice  int  not null default 0 comment '单价,单位分',  

category  varchar(12) comment '商品分类',  

provider  varchar(64) not null comment '供应商名称'

);

//客户

create table if not exists customer (   

customer_id  int primary key auto_increment comment '客户编号',  

name varchar(32) not null comment '客户姓名',  

address  varchar(256) comment '客户地址',  

email  varchar(64) unique key comment '电子邮箱',  

sex  enum('男','女') not null comment '性别',  

card_id char(18) unique key comment '身份证'

);

//购买

create table if not exists purchase (  

order_id  int primary key auto_increment comment '订单号',  

customer_id int comment '客户编号',  

goods_id  int comment '商品编号',  

nums  int default 0 comment '购买数量',  

foreign key (customer_id) references customer(customer_id),  

foreign key (goods_id) references goods(goods_id)

);

关系图如下