【MySQL-表的约束】空属性+默认值+列描述+zerofill+主键+自增长+唯一键+外键+综合案例

表的约束

真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如一个字段是email,要求是唯一的

表的约束很多,这里主要介绍如下几个:null/not null,defult,comment,zerofill,primary key,auto_increment,unique key

表的约束:表中一定要有各种约束,通过约束,让我们未来插入数据库表中的数据是符合预期的。约束本质是通过技术手段,倒逼程序员,插入正确的数据。反过来,站在mysql视角,凡是插入进来的数据,都是符合预期的

约束的最终目标:保证数据的完整性和可预期性,因此我们需要更多的约束条件

一、空属性

  • 两个值:null(默认的)和not null(不为空)
  • 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算
  • null就是null,null不是0,null不是空串

在这里插入图片描述

案例:创建一个班级表,包含班级名和班级所在的教室

站在正常的业务逻辑中:

◉ 如果班级没有名字,你不知道你在哪个班级

◉ 如果教室名字可以为空,就不知道在哪上课

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

create table class_info(
	name varchar(20) not null,
	room varchar(10) null
);

在这里插入图片描述

insert into class_info values('张三','大数据1班');
insert into class_info values('李四',null);
insert into class_info values(null,null);

由于name设置了not null 约束,只要插入的数据字段为null,mysql将拒绝插入

在这里插入图片描述

在这里插入图片描述

二、默认值

默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择下的使用默认值。

mysql> create table t1(
    -> name varchar(20) not null,
    -> age tinyint unsigned default 0,
    -> sex char(2) default '男'
    -> );
Query OK, 0 rows affected (0.04 sec)

mysql> desc t1;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| name  | varchar(20)      | NO   |     | NULL    |       |
| age   | tinyint unsigned | YES  |     | 0       |       |
| sex   | char(2)          | YES  |     | 男      |       |
+-------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

默认值的生效:数据在插入的时候不给该字段赋值,就使用默认值

mysql> insert into t1(name) values('张三');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1;
+--------+------+------+
| name   | age  | sex  |
+--------+------+------+
| 张三   |    0 | 男   |
+--------+------+------+
1 row in set (0.00 sec)

--注意:只有设置了default的列,才可以在插入值的时候,对列进行省略

🌟:default 和 not null不冲突,而是互相补充的;当用户向插入的时候,要么是NULL,要么是合法数据

在这里插入图片描述

现在创建一个表test,其中id 不能为null ,默认为0

tel 可以为null,默认为123123

mysql> create table test(
    -> id int not null default 0,
    -> tel varchar(13) default '123123'
    -> );

在这里插入图片描述

insert into test values(null,'111111');
insert into test(tel) values('234234');

not null 只是不能插入null,不代表不能不插入数据;

我们只插入tel的时候,id自动填充为0

在这里插入图片描述

三、列描述

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

create table t2(
	name varchar(20) not null comment '姓名',
	age tinyint unsigned default 0 comment '年龄',
	sex char(2) default '男' comment '性别'
);

通过desc查看不到注释信息:

在这里插入图片描述

通过show可以看到:

show create table t2\G;

在这里插入图片描述

四、zerofill

在MySQL数据库中,ZEROFILL是一个属性,可以用于数字类型的数据列(如INT, FLOAT等)。当你在创建表时为某个数字列指定ZEROFILL属性,如果该列的值小于列定义时的宽度,MySQL会在该值的左侧填充零以达到指定的宽度。

例如,如果你有一个INT类型的列,并且指定了宽度为5,同时使用了ZEROFILL

create table testZeroFill(
	num int(5) zerofill
);

在这里插入图片描述

insert into testZeroFill values (99);

在这里插入图片描述

需要注意的是,ZEROFILL也会隐式地将该列定义为UNSIGNED,即使你没有明确指定。这意味着你不能在该列中存储负数。

此外,ZEROFILL只影响显示的值,并不改变实际存储在数据库中的值。实际存储的值是不包含前导零的。

五、主键

在数据库管理系统中,主键(Primary Key)是一个非常重要的概念。它是用于唯一标识表中每一行(或记录)的一个或一组列。

主键具有唯一性(表中的每一行都必须有一个唯一的主键值。这意味着主键列不能有重复的值),非空性(主键列不能包含NULL值),不变性(一旦一个主键值被分配给一行数据,它就不能被更改或更新);

1.简单主键

简单主键:只由一个列组成的主键。

案例:

  • 创建表的时候直接在字段上指定主键
create table t3(
	id int unsigned primary key comment '学号不能为空',
  name varchar(20) not null
);

在这里插入图片描述

  • 主键约束:主键对应的字段中不能重复,一旦重复,操作失败
insert into t3 values(1,'aaa');
insert into t3 values(1,'bbb');

在这里插入图片描述

  • 当表创建好以后但是没有主键的时候,可以再次追加主键
alter table 表名 add primary key(字段列表)

在这里插入图片描述

  • 删除主键:由于主键一张表内只有一个,所以不需要指定字段
alter table 表名 drop primary key;

在这里插入图片描述

2.复合主键

一张表中最多只能有一个主键,不意味着一个表中的主键,只能添加给一列;一个主键可以被添加到一列,或者多列上

复合主键:由两个或更多列组成的主键。当单个列不能唯一标识一行时,可以使用复合主键。

例如:一个学生只能选一门课程,不能一个学生把同门课程选很多次

 create table t4( 
   name varchar(20), 
   courseid int, 
   primary key(name,courseid) 
 );

在这里插入图片描述

insert into t4 values('张三','001');
insert into t4 values('张三','002');
insert into t4 values('李四','001');
insert into t4 values('张三','001');

由此可见name 和 courseid 两列合成主键,主键还是一个,只不过添加给了两个字段;

主键的唯一性是指:主键内的所有数据不能有重复值,只要有一个与主键值不一样,那就不是唯一的

在这里插入图片描述

六、自增长

auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值 +1 操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键

自增长的特点:

◉ 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)

◉ 自增长字段必须是整数

◉ 一张表最多只能有一个自增长

案例:

create table t5(
	id int unsigned primary key auto_increment,
  name varchar(10) not null default ''
);

在这里插入图片描述

insert into t5(name) values('a');
insert into t5(name) values('b');

在这里插入图片描述

在插入后,可以通过select last_insert_id();获取上次插入的 AUTO_INCREMENT 的值(批量插入获取的是第一个值)

在这里插入图片描述

此时我们插入一个id 为100的;下一次不指定id插入的时候,就从101开始自增

insert into t5(id, name) values(100,'c');
insert into t5(name) values('d');
insert into t5(name) values('e');

在这里插入图片描述

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

​ 索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。

​ 数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息。

关于更多关于索引的信息,我们后期专门出专题讲

七、唯一键

一张表中往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题

唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较

关于唯一键和主键的区别:我们可以简单理解成,主键更多的是标识唯一性的,而唯一键更多的是保证在业务上,不要和别的信息出现重复。乍一听好像没啥区别,我们举一个例子

假设一个场景(当然,具体可能并不是这样,仅仅为了帮助大家理解)
比如在公司,我们需要一个员工管理系统,系统中有一个员工表,员工表中有两列信息,一个身份证号码,一
个是员工工号,我们可以选择身份号码作为主键。

而我们设计员工工号的时候,需要一种约束:而所有的员工工号都不能重复。

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

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

案例:

create table t6(
  id char(10) unique comment '学号,不能重复,但可以为空',
  name varchar(10)
);

在这里插入图片描述

insert into t6(id, name) values('01', 'aaa');
insert into t6(id, name) values('01', 'bbb');#唯一约束不能重复
insert into t6(id, name) values('null', 'bbb');#但可以为空

在这里插入图片描述

insert into t6(id, name) values('null', 'ccc');

再次插入id为null失败的原因是:表中已经有id为null字段了,id有唯一键约束,再次插入null就会发生冲突

在这里插入图片描述

八、外键

外键约束(Foreign Key Constraint)是关系型数据库中用于维护数据一致性引用完整性的一种机制。它定义了一个表中的列与另一个表中的主键之间的关系

外键用于定义在主表从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique(唯一键)约束,要求外键列数据必须在主表的主键列存在或为null

语法:

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

案例:现在有两张表,学生表和班级表;一定是先有班级,才有学生;索引学生表是从表,班级表是主表

在这里插入图片描述

如果将班级表中的数据都设计在每个学生表的后面,那就会出现数据冗余,所以我们只要设计成让stu->class_id 和 myclass->id形成关联的关系=>外键约束

对上面的示意图进行设计

◉ 先创建班级表(主表)

create table myclass(
  id int primary key,
  name varchar(30) not null comment'班级名'
);

◉ 再创建从表

create table stu(
	id int primary key,
  name varchar(20) not null comment '学生名',
  class_id int,
  foreign key(class_id) references myclass(id)
);

在这里插入图片描述

◉ 正常插入数据

insert into myclass values(10, 'C++大牛班'),(20, 'java大神班');

在这里插入图片描述

insert into stu values(100, '张三', 10),(101, '李四', 20);

在这里插入图片描述

◉ 插入班级号为30的学生,因为没有这个班级,所以插入不成功

insert into stu values(102, '王五', 30);

在这里插入图片描述

◉ 插入班级id为null,比如来了一个学生,目前还没有分配班级

insert into stu values(102, '王五', null);

在这里插入图片描述

首先我们承认,这个世界是数据很多都是相关性的。

理论上,上面的例子,我们不创建外键约束,就正常建立学生表,以及班级表,该有的字段我们都有。

此时,在实际使用的时候,可能会出现什么问题?
有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中?
比如某个学校只开了100班,101班,但是在上课的学生里面竟然有102班的学生(这个班目前并
不存在),这很明显是有问题的。

因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题。

解决方案就是通过外键完成的。建立外键的本质其实就是把相关性交给mysq1去审核了,提前告诉mysql
表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入。

九、综合案例

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

  • 商品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 bit32mall default character set utf8;

-- 选择数据库
use bit32mall;

-- 创建数据库表
-- 商品
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)
);