表中一定要有各种约束,通过约束让我们在未来使用数据库的时候,操作的结果都能是符合预期的!约束的本质就是通过技术手段倒闭程序员插入正确的数据!
真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,这是为了更好地保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是 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
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或**DBA**(Database Administrator 数据库管理员)来进行了解。
要查看的话一般要通过 show create table table_name \G 来进行查看!
Ⅳ. 零填充zerofill
想必刚学数据库的时候,大伙都会对下图中红色框中的内容感到疑惑吧:
要说 varchar(20) 类型后面跟着的数字是字符的长度还能理解,但是一个整数类型为啥也有长度,还是说这不是长度❓❓❓
其实整数类型后面的括号中的数字表示的是零填充的宽度!举个例子,如果是 int(4) 的话,表示零填充的宽度为 4,此时我们插入一个值为 300,它的长度是 3,小于零填充的宽度 4,所以当我们查询结果的时候,会看到返回的是 0300,也就是默认在前面填充 0 直到达到零填充的宽度为止!
如果我们要看到这个显示效果的话,必须配合一个关键字属性 zerofill,不然是没有意义的!
下面我们创建一个表来看看不同的宽度有什么效果:
至于为什么 int 类型默认是 10,这是因为 int 的最大范围就是十位数!
Ⅴ. 主键 primary key
1、主键的特性和创建
主键:primary key 用来唯一的约束该字段里面的数据,它有如下的特点:
- 主键值不能重复,因为具有唯一性
- 主键值不能为空
- 一张表中最多只能有一个主键(但不意味着一个表中的主键,只能添加给一列)
- 主键所在的列通常是整数类型
比如说下面我们创建一张表,让 id 字段带上主键约束:
2、追加和删除主键
当表创建好以后但是没有主键的时候,可以再次追加主键,用如下语句:
alter table 表名 add primary key(字段列表) 如果需要删除主键的话,可以用如下语句:
alter table 表名 drop primary key;
有个注意事项:在追加主键之前,需要确保要添加主键的那个字段不能出现重复值!
3、复合主键
在创建表的时候,在所有字段之后,使用 primary key(主键字段列表) 来创建主键,如果有多个字段作为主键,可以使用复合主键。
什么,上面不是说表中主键只能有一个吗,这不是自相矛盾吗❓❓❓
是的,表中主键就是只能有一个,但是谁说这唯一的主键就不能分配给多个列字段呢,对不对!我们上面那种直接在列字段后添加
primary key属性代表的意思是创建一个独立的主键,所以两个列字段都申请要主键,那就肯定报错啦! 而如果单独用
primary key(主键字段列表)来表示的话,说明只创建一个主键,只不过该主键是由两个列字段组成的而已! 所以这种说法是不矛盾的!
值得注意的是,因为主键由两个或多个列字段组合而成,所以它们也需要表示唯一性,这体现在多个字段值组合的时候,不能出现重复的值组合。下面举个例子来解释一下:
Ⅵ. 自增长 auto increment
auto_increment:当对应的字段不填值的时候,会自动的被系统触发,系统会从当前字段中已经有的最大值进行 +1 操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。
自增长的特点如下所示:
- 任何一个字段要做自增长,前提是本身是一个索引(索引后面会讲!)
- 自增长字段必须是整数
- 一张表最多只能有一个自增长
下面举个例子就懂了:
然后我们试着插入一些元素,看看自增长规律:
为什么我们插入了 3000 之后,系统就知道此时要从 3001 开始自增长呢❓❓❓
其实是因为 mysql 肯定也会有属性用来记录当前自增长字段的最大值,如下所示:
并且我们还可以通过一个函数 last_insert_id() 来查看上次插入的自增长的值是多少:
那这是不是意味着,我们也可以设定一下当前的自增长的起始值,答案是肯定的,如下所示:
索引简介:
在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。
索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的
SQL语句执行得更快,可快速访问数据库表中的特定信息。
Ⅶ. 唯一键 unique
在 mysql 中,唯一键(Unique Key)是一种约束,用于确保表中的某个列或一组列的值是唯一的,防止重复数据的插入或更新。在创建表时,可以通过在列定义中使用 unique 关键字来指定唯一键!
它和主键的唯一区别就是如果该列字段没有设置 not null 的话,那么定义为唯一键的话是可以插入 null 值的,而主键则不可以插入 null 值!
问题来了,不是已经有一个主键
primary key了吗,为啥还需要一个唯一键,这不是多此一举吗❓❓❓ 其实并不会!并且它们的关系其实是互补的!假设有以下场景:
比如在公司,我们需要一个员工管理系统,系统中有一个员工表,员工表中有两列信息,一个身份证号码,一个是员工工号,我们可以选择身份号码作为主键。
而我们设计员工工号的时候,需要一种约束:而所有的员工工号都不能重复。这具体指的是在公司的业务上不能重复,我们设计表的时候,需要这个约束,那么就可以将员工工号设计成为唯一键。
所以一般而言,我们建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对主键做过大的调整。
而会将与业务有关的并且不能重复的字段设计为唯一键!
下面来举个例子大家就懂了,我们创建一个表,其中 id 字段是作为主键,然后其它字段我们先不设置唯一键:
很明显就能看到问题,虽说我们创建了主键来标识每个用户,但是用户的手机号和qq号还是会出现重复的情况,这可能是因为在录入信息的时候的错误操作,但是归根结底,是我们数据库的表设计的不好!
为了防止这种情况,因为主键只能创建一个,所以我们可以用唯一键来进行字段的标识,保证其唯一性:
可以看到唯一键是可以插入空值的,代表该项信息是没有的,这是因为唯一键的工作就是为了防止字段值重复而已!
可能会有人问,那我们不是学了复合主键吗,为什么不用复合主键来代替唯一键呢❓❓❓
这个问题不错,但是结合上面的例子再仔细一想就知道,我们日常生活中有很多与别人不重复的信息,但是有些别人有的信息,咱们不一定有,所以得有
null的存在,但是复合主键的特点之一是不能为空,这就导致了和我们的意愿不符合的情况,所以必须要有唯一键!
Ⅷ. 外键
外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有 primary key 约束或 unique 约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为 null。
语法如下所示:
foreign key (字段名) references 主表(列) 首先我们要知道现实生活中的数据很多都是相关。
比如说一个学生和班级的关系,学生是隶属于一个班级的,此时如果我们创建两张表,一张用来描述学生,一张用来表述班级。此时,在实际使用的时候,可能会出现什么问题❓❓❓有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中❓❓❓
比如学校只有
101班和102班,但是在上课的学生里面竟然有在103班的学生(这个班目前并不存在),这很明显是有问题的。 因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题!
解决方案就是通过外键来创建表与表之间的约束关系!建立外键的本质其实就是把相关性交给
mysql去审核了,提前告诉mysql表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入。
下面我们先创建两张表,一张描述学生,一张描述班级,并且先不创建外键,来看看一些错误情况:
很明显看到这不是正常的情况,所以我们必须要建立外键,让两个表的班级字段关联起来!
上面两个表的情况,其实是有外键之名(关联关系),但是没有外键之实(没有约束),所以导致了两张表的逻辑搭不上边!
下面我们就来创建外键,首先我们要确定的是,班级表应该是主表,而学生表应该是从表,因为学生隶属于一个班级!搞清楚了关系之后我们先来创建一张学生表,此时的学生表要创建外键关联上主表也就是班级表,操作如下所示:

此时要是插入班级 class_id 为 null 也是可以的,就好比来了一个学生,目前还没有分配班级!
最后再来看看创建表语句中的内容:
Ⅸ. 综合案例
有一个商店的数据,记录客户及购物情况,有以下三个表组成:
- 商品
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 enum('水果', '零食', '蔬菜') 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)
);