作者:小树苗渴望变成参天大树
作者宣言:认真写好每一篇博客
作者gitee:gitee✨
作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!
今天我们开始讲解表的约束,对于约束上一篇已经提到过了,目的就是让插入表的数据更加的符合我们的预期,我们单单使用数据类型进行约束时远远不够的,例如,姓名和爱好,都设置成varchar类型,那就会出现将爱好插入到姓名的可能,这样就造成数据错乱的问题,所以我们还需要更多的约束去让我们程序员规范的插入数据。真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的 表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofill,primarykey,auto_increment,unique key
。
为什么我们sql要这么严格规范插入数据的合理合法性呢??
原因是数据库是维护用户数据的最后一道防线,对于一些个人信息,财产的数据,出现错误就不是小错误了,所以sql要非常严格,不仅仅对程序员要严格,也是为了严格的保护用户数据
两个值:null(默认的)和not null(不为空)
数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办
法参与运算。
sql里面的null不代表0就表示什么都没有,null和‘’‘’是不一样的,一个是什么内容都没有,另一个是有内容表示的是空串。
案例:
创建一个班级表,包含班级名和班级所在的教室。
站在正常的业务逻辑中:
所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是“约束”。
//直接在数据类型后面加上约束条件就可以了
create table myclass(
class_name varchar(20) not null,
class_room varchar(10) not null);
我们看到前两次插入可以插进去可以理解,前两个属性没有为空,第三个属性可以为空,后面两个属性插入失败也可以理解,第二个属性你不插入数据或者插入null都是不符合约束的,但是错误信息不一样,这是为什么??,一会解释
上面的约束还有一个小问题要解决,我们先来学习完下面的这一个属性。
默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择性的使用默认值。
create table tt10 (
name varchar(20) not null,
age tinyint unsigned default 0,
sex char(2) default '男'
);
我们看到将设置成有默认值的属性插入数据,就是要我们插入的,没有插入才是要默认的。
接下来用一张表带大家在来了解一下空属性和默认值。
create table test(
name varchar(20),
age tinyint default 18,
gerder char(2) not null default '男');
有默认值的列,在插入值的时候可以对列进行省略,只有默认值,插入null也是可以的,因为没有notnull进行约束。
我们再来看一张表:
create table test1(
name,varchar(20),
age tinyint);
这是一张没有约束的表,我们将age列省略了,我这创建表的时候也没有设置默认值,按照上面的数据,只有设置了默认值的列在插入的时候才可以省略,那应该会报错,但是结果是插入成功了,原因是sql是进行优化,你没有设置notnull,sql就会给你设置一个默认值为null,如果你设置了notnull,那么sql就不会给你生成默认值了。这个大家下去在测试一下。
大家完全不用担心,因为not null一般不和默认值一起设置,你设置了默认值,就意味着不为空,但是sql语法支持这样一起设置,我们后面使用的时候一般设置一个就可以了,大概率不会一起设置的。
大家对于第一节的问题有没有答案了呢,第一个省略了没有默认值的列,所以会报没有默认值的错误,第二个有notnull你插入null会肯定先报notnull的错误。
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。
这个是方便我们管理员查看你插入的数据和描述的内容是不是一样的,也方便管理员知道每一列表达的含义是什么,才能更好的管理数据。
刚开始学习数据库时,很多人对数字类型后面的长度很迷茫。
我们创建一个表:
create table test3(
a int unsigned,
b int);
可以看到int(10),int(11)这个代表什么意思呢?整型不是4字节码?这个10又代表什么呢?其实没有zerofill这个属性,括号内的数字是毫无意义的。a和b列就是前面插入的数据,如下:
但是对列添加了zerofill属性后,显示的结果就有所不同了。修改tt3表的属性:
alter table test3 modify a int zerofill;
这次可以看到a的值由原来的1变成0000000001,这就是zerofill属性的作用,如果宽度小于设定的宽度(这里设置的是10),自动填充0。要注意的是,这只是最后显示的结果,在MySQL中实际存储的还是1。为什么是这样呢?我们可以用hex函数来证明:
我们看到不够设置的数字大小就补0,超过了,是多少就是多少,是至少的行为。也算是一种格式化输出的形式。
为什么有这个设计:原因有的场景需要,它需要插入的数据长度是一样的,显示效果好,比如班级的显示,都是固定长度
为什么我们的int默认后面的数字是11,unsigned int 默认的是10,大家都知道我们int的范围不论是在有符号还是无符号都是21亿或者是42亿,这些数字最大也只占10为,有符号的多一位了是因为要显示负号
主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型 ,主键的作用是方便去查询
案例:
create table tt13 (
id int unsigned primary key comment '学号不能为空',
name varchar(20) not null);
被设置为主键的列自动加上notnull。并且默认值为NULL,所以插入的时候必须要有数据。不能省略行。
insert into tt13 values(1, 'aaa');//插入两次
alter table tt13 drop primary key;
可以去掉主键,但是空属性还是不变,我们发现去掉主键可以插入重复的数据了。
alter table tt13 add aprimary key(id);
我们的id里面有相同的数据,所以设置成主键就会出现错误,所以要删除,那我们也不知道删除那一个,都有可能造成数据的损失,所以主键一般不要再中途加,创建表的时候就设置好。
create table tt14(
id int unsigned comment'学号',
course char(10) comment'课程号',
primary key(id,course));//id和course为符合主键,一个属性为主键的时候也可以这样写。
通过查看表结构来看,我们的两个属性都不准为空,而且都有默认值,id的默认值是0,course的默认值是空格,它不是表示NULL。
通过上面的测试我们知道符合主键的特点了,它不能为空,并且有自己的默认值,所以插入的时候对应的列可以省略,和单个属性是主键有差别,它不能为空,但是默认值为NULL,所以它插入的时候必须要插入数据,不能使用默认值。这个大家要清楚。
注意:我们发现除了单个属性作为主键可以控制此属性是唯一的,而复合主键不行,保证不了任何一个属性的唯一性,万一此表有多列属性需要唯一性去约束怎么办??此时有了一个新的约束叫做唯一键。
我们在入学的时候,老师们需要录取我们的信息,我们都知道学号是标识我们每个人的,所以学号是唯一的,我么需要将他设置成主键,但是每个人的手机号也是唯一的,此时不能再设置一个主键了,所以我们需要将电话号设置成唯一键,来保证它的唯一性。
案例:
create table tt15(
id int unsigned,
name varchar(20) not null,
telphone char(11) unique key,
primary key(id));
我们看到表结构第三行是唯一键,但是它可以为空,这是它和主键的区别,如果将主键写在属性后面就没有默认值,写在最后就会有默认值。
理解主键和唯一键:
我们的一张表中可能有多个属性需要保证它的唯一性,通过第五节的测试来看,主键不能没有这样的功能,所以唯一键是必须的,其次单个属性表示的主键是由唯一性的,所以主键是从多个具有唯一性的属性中挑出来的,也可以选择其他具有唯一性的属性列。这是选择的问题。两者的本质是:主键不能为空,唯一键可以为空,空字段不做唯一性比较。两者的区别是:我们可以简单理解成,主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复,但一个唯一键设置了非空,其实你也可以将他当成主键。
auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。
自增长的特点:
create table tt16(
id int unsigned primary key auto_increment,
name varchar(20) not null);
我们设置了自增长的属性,再插入的时候可以不用管,但是你要插入也是可以的。
我们看到默认值从1开始的,如果自己插入了数据就按照自己插入的算,下次自增长从上行的数据开始增加。
我们看到由变量记录下次自增长的数字是多少,所以我们再创建表的时候设置初始值就可以了。
如果你插入了id是1,2,3,但是你删除了2这一行数据,下次插入只会从插入4,不会插入2,除非你指定。
外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null
假设c++大牛班有100人,java大神班有120人,如果再一张表中,那么班级这一列就会出现数据冗余,所以需要把表进行分开,两张表多加一个属性,让着两个属性产生关联。有的人会说这两个多家的属性不也冗余,但是节省空间了,并且降低了耦合度。
我们来看看案例:
我们需要设计两个表,班级表是主表,学生表是从表。
create table myclass (
id int primary key,
name varchar(30) not null comment'班级名'
);
create table stu (
id int primary key,
name varchar(30) not null comment '学生名',
class_id int,
foreign key (class_id) references myclass(id)
);
再主表和从表中插入数据:
通过结果来看,我们发现主表中没有的数据,再从表中插入不进去,那么我们万一想要删除主表的数据呢??
我们发现从表里面还有数据和主表的数据关联,所以删除失败,但从表的数据和主表的没有关联了,就可以删除成功了。
大家可以通过班级和班级的学生来想上面的问题。
如何理解外键:
首先我们承认,这个世界是数据很多都是相关性的。
理论上,上面的例子,我们不创建外键约束,就正常建立学生表,以及班级表,该有的字段我们都有。
此时,在实际使用的时候,可能会出现什么问题?
有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中?
比如学校只开了100班,101班,但是在上课的学生里面竟然有102班的学生(这个班目前并不存在),这很明显是有问题的。
因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题。
解决方案就是通过外键完成的。建立外键的本质其实就是把相关性交给mysql去审核了,提前告诉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)
);
我们这篇讲解了关于表的约束,使我们再插入数据的时候更加合法了,大家还是要下来自己去测试一下每种约束的特点,这样印象会更加深刻,但是这一系列操作都是再定义表,还是属于数据定义语言层面,下一篇我们开始介绍数据操纵语言,前面想当于定义好结构,下一篇开始进行操作。希望大家过来支持博主