详解MySQL字段约束

发布于:2023-01-04 ⋅ 阅读:(727) ⋅ 点赞:(0)

写在前面

我们已经会创建数据表了,不过有时候会看到not null等字样,这些便是字段约束的内容,我们好好看一看什么是约束,又有哪些约束,这份博客时纯理论的,我们自己要理解这里面的内容

什么是字段约束

简而言之,字段约束就是将字段的内容定一个规则,我们要按照规则办事,常见的字段约束有下面几个

约束的分类

这里我们先把约束给大家列出来,后面都会谈到.

  • not null – 指示某列不能存储 NULL 值
  • unique – 保证某列的每行必须有唯一的值
  • default – 规定没有给列赋值时的默认值
  • **primary key ** – not null 和 unique 的结合。确保某列(或两个列多个列的结合)有唯一标
    识,有助于更容易更快速地找到表中的一个特定的记录
  • foreign key – 保证一个表中的数据匹配另一个表中的值的参照完整性
  • check – 保证列中的值符合指定的条件。对于MySQL数据库,对check子句进行分析,但是忽略
    check子句 ,我们不太常用,就不说了

为何要有字段约束

  • 保证数据的完整性
  • 保证数据的有效性

完整性

我们有时候填表会发现有些是必填项,这里就是not null的作用,他要求这个表格不能为空,获取我们完整的信息

有效性

在这里我们假设一个个场景,要是张三的电话号码是123×××××××45,那么李四的电话号码绝对不会和张三一摸一样,这里就体现出unique的作用了

我们先创建一个表格,来仔细看看

create table books(
    book_id char(10) not null,
    book_name varchar(20) unique,
    book_price int
);

在这里插入图片描述

非空约束 not null

非空约束比较简单,就是要求我们不能为空,命令为 not null

在上面我们就看到了这行代码 book_id char(10) not null, 这就是说book_id不可以为空

在这里插入图片描述

我们观察一下表结构,你就会发现在null这一列id是禁止为空的.

image-20220831171551724

唯一约束 unique

这里也很简单,唯一 的意思就是各不相同,代码是**book_name varchar(20) unique,**这里就不演示表结构了,上面的key中的name的UNI就是唯一的.

在这里插入图片描述

默认值约束 default

这个时定义默认值的,要是我们不定义,它是NULL,如果我们设置了,这就会改变.我们重新创建表.

create table books(
    book_id char(10),
    book_name varchar(20) default 'unknow',
    book_price int
);

image-20220831172912705

image-20220311193658720

我们先测试一下,只要我们插入数据,都会把这个数据保存下来,无论是不是null.

insert into types values (1,NULL,'测试');  

image-20220311194916856

一旦我们部分列插入,没有插入的数据就会变成默认值.

insert into types (type_id,type_remark)values (1,'测试');   --  部分列插入

image-20220311195017392

主键约束 primary key

这个约束我们在MySQL中最常用到的约束,这里的主键约束相当于唯一约束和非空约束的集合,不过也会有一些另外的不同.

  1. 主键约束 = 非空约束 + 唯一约束
  2. 主键约束也是一个标识,就像人的身份证
  3. 主键一个表只能存在一个,而且一个主键只能作为一列.

创建主键

我们最好每一张数据表都创建一个主键,后面我们用到索引的时候会说一下原因

我们在创建字段的时候指定.

create table Persons(
    per_id char(10),
    per_name char(12),
    per_age int(3),
    per_tele char(10) primary key  --  创建字段时指定
);

也可以在创建表的最后指定主键,不过要把字段和类型说完整,当然不完整也是可以的,但是这种方法我们一般不用,都是在字段后面直接指定主键的.

create table Persons(
    per_id char(10),
    per_name char(12),
    per_age int(3),
    per_tele char(10),
    primary key(per_tele char(10))   --   最后指定
);

image-20220831175557738

删除主键

这里就体现出主键约束和其他的一些不同,我们删除时就不需要看具体的字段

alter table Persons drop primary key;      

在这里插入图片描述

添加主键

对于一张没有主键的表,我们也可以等后面给他添加上.

alter table Persons modify per_tele char(10) primary key; -- modify 调整

在这里插入图片描述

不能为空

这里我们就要看一下什么叫做不能为空,对于简单的默认值是null我们就不看了,这里重点看一下默认值是其他的时候,看看效果如何.我们先来创建一个表.

create table books(
    book_id char(10),
    book_name varchar(20) primary key default 'unknow',
    book_price int
);

image-20220831180131155

这里我们部分列插入数据,先来插入一行看看效果.

insert into books (book_id,book_price)values ('123',15);

image-20220831180501436

从这里看我们成功了,也就是是说,所谓的不能为空,就是数据不能是null.

不能相同

这个就不给大家解释这么多了,我们再次插入一下数据.这里就会报错,原因就逐渐的数据是不能重复的,要知道默认值是一样的,所以报错.

insert into books (book_id,book_price)values ('456',20);

image-20220831180715811

主键的自动增长

在实际生活中,我们可能会遇到这么一个问题,很多字段我们不能保证他们不为空或者是两两不同的,我们可以创建出一个额外的字段让他们好寻找,自然而然的就会以1、2、3、…来标识,不过这也太麻烦了,我们出现了自动增长的形式

create table types(
    type_id int primary key auto_increment,
    type_name varchar(20),
    type_remark char(11)
);

image-20220311192655896

这个代码将type_id设置为自动增长主键

我们先来插入一个数据,对于自动增长的主键,这里我们先来设置为null.

insert into types values (null,'123','20');

image-20220831181147460

这里我们就会发现,对自动增长的主键,我们即使设置为null,他也会从1开始自动增长.

image-20220831181424770

这里我们闲来测试一下如果我们只是插入部分列,看一下自动主键是不是会增长.

insert into types (type_name,type_remark)values ('789','20');

image-20220831181548899

从这我们就可一看到就看到,对于自动增长的主键,我们无论是指定null,还是不做数据的插入,都会自己加上1.

不过自动增长也有一些缺陷,要是我们删除一行,其他的type_id的值是不变的,也就是我们删除了中间数据,后面的自动增长的主键的值是不是改变的

delete from types where type_name = '456';  -- 可以 用 = 判断字符类型

image-20220831182438482

这里我好好解释一下,只要我们添加了一行数据,他就会+1,即使我们后来删除了,它也不会 -1,是一直加的

image-20220831182816597

这里还需要指出,如果我们明确指出主键的确定值,这个主键值就变了.之后再次插入,主键值还是相对于上一个+1.这里就不演示了.

image-20220831182932134

联合主键

这里我先建一个数据表格,这张表中我们会发现,我们学生和课程只有在一起我们才能得到真实的成绩。所以这就出现了联合主键,联合主键,顾名思义就是多个主键联合形成一个主键组合,体现在联合.

在这里插入图片描述

我发现这里的字段都不能作为主键,但是学生课程连在一起却可以,这就是联合主键

如何定义联合主键

create table grades(
	stu_name char(10),
	stu_class char(5),
	stu_grade int,
	primary key(stu_name,stu_class)  --  stu_name 和 stu_class 一起 定义主键
);

在这里插入图片描述

这里面提示一下我们很少使用联合主键,我们可以额外提供一个字段作为识别

外键约束

我们可能会疑惑什么是外键约束,我直接说一下,外键约束时联系多张表的约束,下面我用例子为大家说明一下我们先创建两张表

-- 班级表
create table class(
    id int primary key auto_increment,
    name varchar(20)
);
-- 学生表
create table student(
    id int primary key auto_increment,
    name varchar(20),
    classId int 
);

image-20220311223532002

每一个同学肯定是属于一个班级的,我们向往班级表中插入一些数据

insert into class values 
(null ,'java1班'),
(null ,'java2班'),
(null ,'java3班'),
(null ,'java4班');

image-20220311224237207

下面我们可以假设这样一个场景,有一名同学叫做 李白,在 java1班学习,我们可以这么记录

insert into student values (null,'李白',1);      --   java1班 的id  是1

image-20220311225017985

上面的情况很正常,但要是我们下面这么插入数据.

insert into student values (null,'杜甫',100);

image-20220831183618686

我们没有id 是100的班级,但是我们也成功插入了,这就和实际产生了差异,这就引出了外键约束。外键很简单,要是两张表有联系就可以使用外键约束

正确使用外键

我们向把班级表和学生表删除,重新创建.不过在之前,我们先来提一个结论.我们喜欢把班级表这种叫做父表,学生表叫做子表.

drop tables class,student; -- 这里语法支持的

我们这里重新创建一下班级表,这里后面在解释.

-- 创建班级表     不变
create table class(
    id int primary key auto_increment,
    name varchar(20)
);
-- 添加数据
insert into class values 
(null ,'java1班'),
(null ,'java2班'),
(null ,'java3班'),
(null ,'java4班');

创捷学生表就比较麻烦了,主要是外键的创建有些麻烦,我们先列出格式

foreign key(本表的字段) references 其他表的表名(其他表的表名的字段)  -- ()号是存在的
create table student(
    id int primary key auto_increment,
    name varchar(20),
    classId int,
    foreign key(classId) references class(id) --   解释这句话 我们定义一个外键,是classId,链接 class表中的  id  字段
);

image-20220311230413111

当我们开始插入数据后,MySQL会自动帮助我们进行校验,我们来几次

insert into student values 
(null,'李白',1),
(null,'刘备',2),
(null,'曹操',3),
(null,'杜甫',3);

image-20220831190441122

但我们插入class中不存在的id时,出现错误.这是由于在班级表中找不到id为10的班级,所以不能插入成功.

insert into student values (null,'错误',10);  

image-20220311231214545

外键约束的缺陷

我们使用外键会有一些小问题的。

  • 效率有些低,我们插入数据时要查询另一张表的数据,索引中我们会提高效率
  • 不太能删除被关联的表,下面我用代码表示一下

这里我们解释一下第二个,一旦我们把班级表给删除掉,你就会发现自己不能这么做.原因就是这个表被一个表依附

drop table class;

image-20220311231925496

那么我们对于班级表中的数据可以删除吗?这里要分情况.如果学生表的数据依赖了你要删除的数据,这就不能删,反之可以删.

image-20220831190637141

我们在想不是可以这么想,如果学生表中没有数据,班级表可以删吗?抱歉,不能.

image-20220831190912475

这里我们就有疑惑了,我们知道淘宝商城.对于商城而言,肯定存在一张表来存放商品的id,每一个用户的购物车都存在一张购物表.这个表应该存在一个外键来连接商城表的商品的id.那么我们在想,有的时候商品会下架,那么你的购物车中就会显示这个商品已经没有了.这是怎么做到的,好象不符合我们上面谈到的.

实际上,这种删除不是真正的删除,而是逻辑意义上的,商品表中存在一个isOK的列,商品存在就是1,下架就是0.这就是我们的解决办法有的人可能会感到疑惑,那么这张商品表不是越来越大吗,是的,但是我们要记住,现在硬盘不值钱,所以数据多了也没事.