MySQL表的约束
- 约束的概念
- 空属性
- 默认值
- 列描述
- zerofill
- 主键
- 自增长
- 唯一键
- 外键
约束的概念
在正式谈MySQL表的约束之前,我们先来简单理解一下约束这个概念;
约束:意思是指带有束缚、限制、管束等意思;
大白话就是说:规定了那些事情你不能干,那些事情你可以干,那些事情你干了就会出问题,那些事情你干了不会出问题,这也就倒逼我们办事的人只有按照“规则”才能将事情办好,这相对于我们办事的人来说,我们们就不能随心所欲的办事了,时时刻刻都得考虑"规则"来办事,这样的话,我们最后得到的结果一定是规范化、有规律的一组数据!
MySQL表的约束也是如上面所说,MySQL通过限制列的各种属性,从而来保证插入MySQL数据库的数据一定是有规律的、规范的、可预期的,这样的话MySQL的管理成本自然也就没那大,这也是MySQL数据库高效的原因.
空属性
两个值:
- null(默认的)和not null,这两组关键字是用来限制当前列,再插入数据时是否允许插入null值!
- 数据库列属性的这一字段默认都是null,允许插入null值的!但是在实际开发过程中,竟可能保证字段不为空,因为数据为空,没办法参与运算:
eg:
下面我们用具体的案例来讲解一下:null和not null:
eg:
现在我们创建另一个表结构,其中classId和className字段我们都带上了not null的限制,也就是说不允许插入null值,接着我们来试试插入正常值:
然后我们在试着插入一些空值试试:
我们可以看到无论是classId插入空置或者className插入空值MySQL都会抱一个错误:
ERROR 1048 (23000): Column 'classId' cannot be null
这个错误就是在告诉我们当前值不允许插入空值,这也就要求我们要插入一个合法的数据,不能插入null,这也就保证了MySQL数据库里面的插入的数据一定是可预期的、合法的!
当然上面是not null的约束,接着我们来试一试null 的约束,null的约束就是表示当前列允许插入null值,于是我们可以将classID这一列的属性改为null,表示当前列允许插入null值:
接着我们再来向classId这一列插入null值试一试:
注意:
- 一般情况下,如果我们不显示的指定当前列是否允许插入Null值的话,MySQL会默认允许我们当前列插入null值。验证:
- 这里我们还有一点需要特别注意,就是not null和null的约束是针对用户执行 “插入操作” 时是否允许插入null!而当用户不对这一列进行插入操作的时候就另外一个约束了!也就是下文的default缺省值!因为not null和null这个约束与default这个约束非常容易混淆!这里我们需要提前了解一下;只要记住not null和null约束是针对用户执行插入操作时起作用的!而default约束是针对用户不执行插入操作的时候起作用的就可以了!
默认值
默认值:也就是当用户不给我们这一列传入数据的时候,所使用的值,与C++的缺省参数类似!
如果用户给我们这一列插入了数据,那么就是用用户插入的数据!
如果用户没有给我们这一列插入数据,那么就用该列的缺省值来进行插入!
eg:
现在我们要建一个程序员交友网站,需要一个数据表来记录用户信息
那么由于程序员男性居多,当用户不输入自己的性别的时候,默认在性别一列插入男;
现在我们来正常插入:
现在我们来搞一点容易混淆的东西,我们将sex这一列约束属性设置为not null 和default ‘男’;
现在sex既有not null属性也有default属性,是不是有一点混淆了
我们只需要永远记住not null和null约束是针对插入操作的是否起效的就行!
default约束是正对用户不执行插入操作的时候起效的就行!
这两者是相互补充的互不干扰的!
eg:
mysql> insert into person (name,sex) values(null,'女'); ERROR 1048 (23000): Column 'name' cannot be null
我们来解释第一个报错,第一个报错的主要原因就是我们给name列插入了null值,而name列是带上了not null的约束,也就是说明这一列不允许插入null值,因此MySQL直接报错!insert into person (sex) values('女'); ERROR 1364 (HY000): Field 'name' doesn't have a default value
这个报错的组要原因是因为我们在插入数据的时候没有给name列插入值,因此name列就会触发default的约束!但是啊,name列没有设置缺省值啊!因此就没有数据来进行插入啊,因此最后就会爆报出没有缺省值的错误,可是这是有读者就有疑问了,desc查person列的是否这个表结构中的default列不是显示name列的默认值为NULL吗?怎么会没有缺省值呢?
怎么说呢,实际上name的default确实是没有缺省值的,它这里写个NULL的意思是表示name没有缺省值的意思,具体的话我们要以创建person表的创建语句为主,可以利用show create table person
来查看:
很明显创建语句中并没有为name列带上缺省值,因此这里会出现没有缺省值的错误!!mysql> insert into person (name) values(null); ERROR 1048 (23000): Column 'name' cannot be null
这一列出现错误的主要原因就是我们再给name列插入数据的时候,插入了null值,这是不被允许的因为,name字段带上了not null约束!与此同时这一次插入中我们忽略了sex这一列数据的插入,那么就会触发default缺省值的约束,因此sex这一列的插入最终是由sex的缺省值来完成的,这一点没问题!
总结:
- 只要记住not null和null约束是针对用户执行插入操作时起作用的!而default约束是针对用户不执行插入操作的时候起作用的就可以了!
- 当用户将某一列设置为not null的话,MySQL不会为该列带默认上缺省值!
- 如果用户讲某一列设置为 null的话 ,MySQL是会为该列默认带上缺省值的!缺省值给的就是NULL,所以说一旦desc查表查出来的时候发现default列的值为NULL,我们并不能确定这个NULL是真的表示没有缺省值的意思,还是表示有缺省值只不过这个缺省值为NULL,为此我们需要通过查看当前表结构时的创建语句来判断!
列描述
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。
这个就相当于C/C++中的注释,是用来给数据库管理员看到,相当于是一种软性约束,告诉数据库管理员应该插入那种规则的值,如果用户非要插入不合法的值,那么MySQL数据库方面也没有办法阻拦,比较comment只是一种提示,不能硬性拦截!
细节:
在MySQL中单引号也可以用来引用一个字符串,双引号也可以!
zerofill
如果学过C语言的格式化打印,那么这个zerofill就非常好理解;
zerofill通常都是用来约束整数类型的!
就比如上图:我们知道char括号里面的数字表示这个char类型的大小!
float(m,n)中的m和n分别表示指定长度和精度;
那么int(num) 中这个num是什么意思?
是表示num个字节吗?那么上图中的int(11)是表示int占11个字节吗?显然不是!
实际上整型括号后面的数字表示的是这个字段输出必须是num位;
就比如上图中的int(11)就表示id字段的输出必须以11位的方式来进行输出;
那如果实际位数不足11位呢?
就比如123,很明显不够11位啊!怎么能按造11位输出?
针对不满规定位数的数字MySQL会用空格将其补到11位在输出,就比如:
123 会被MySQL不成123
然后进行输出!
位数刚好够就不说了,直接进行输出!
那么如果位数要是超过规定位数?
直接原样输出就好了,这时候就无视这个输出位数的限制了!
比如:int (3) ,现在我有一个12345要输出,很明显12345的实际位数已经超过了规定的3位标准,那么MySQL直接输出就好了!
eg:
什么?你说补空格不好看?想要补0?
安排!zerofill闪亮登场,我们将id的属性改一下:
int 默认以11作为输出位数,因为int的最大长度是需要11位来表示(INT_MIN)
unsigned int 默认以10作为输出位数,因此unsigned int的做大长度就是10位;
主键
主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型,当然也可以为其它类型!
就比如说一个表中有很多条数据,为了确保能够辨识不同的数据,我们需要用某一列或者多列共同组成一条数据的唯一标识,通过这个唯一标识我们可以快速定位指定数据!
eg:
创建表的时候直接在字段上指定主键:
使用primary key
来指定主键
插入数据:
主键约束:主键对应的字段中不能重复,一旦重复,操作失败:
一旦某个字段被设为了主键,那么这个字段也就不能被插入null值,也就是not null约束,那么自然也就不能使用缺省值插入:
当表创建好以后但是没有主键的时候,可以再次追加主键(但是这是否必须保证你要设置为主键的那一列没有冲突值):
如果这个表中有数据,并且要被设置为主键的那一列还有重复数据,那么主键会设置失败:
alter table tablename drop primary key;
取消主键属性!
复合主键
在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段
作为主键,可以使用复合主键。这并不违背一个表中只有一个主键的原则,主键可以是单一的一列作为主键,也可以是多列合起来作为一个主键!
自增长
auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。(但是实际再测的时候在MySQL中auto_increment只能给主键使用)
自增长的特点:
- 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
- 自增长字段必须是整数(auto_increment默认从1开始biaojiegou1)
- 一张表最多只能有一个自增长
eg:
插入数据:
在插入后获取上次插入的 AUTO_INCREMENT 的值(批量插入获取的是第一个值
注意:
auto_increment与default的功能有点像,都是在用户不输入的时候使用默认值,这也就注定了auto_incremen与default是水火不容的!
一个列有了default属性就不能有auto_increment属性;有了auto_increment就不能有default!
唯一键
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。
唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较。
关于唯一键和主键的区别:
我们可以简单理解成,主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复。乍一听好像没啥区别,我们举一个例子
就比如生活中:
一个学生:有身份证号、姓名、性别、学号、手机号、qq号、家庭住址吧!
如果我们学校要构建一个表结构把这些学生的基本信息管理起来的话,那么可以采用学号来充当该表的主键吧,因为学号肯定是唯一的(别杠为什么不用身份证号…),这样的话我们在插入数据的时候不可能插入两个学号的相同数据,可是有没有可能我们插入数据时失误了,确实是插入了两条学号不一样的数据,但是这两条数据的身份证号却相同、qq号、手机号也相同,这样在数据库层面是没办法识别的,数据库会直接让我们进行插入,但是站在实际的角度这是不合理的!在现实中不可能有两个身份证一样的人、也不可能有两个手机号一样的人、也不可能有两个qq号一样的人!为此,我们在设计数据库时除了要保证主键的列的唯一性,也要保证其它列的合法性!当出现主键列不同,但其它身份证一列相同的情况我们需要在数据库层面做出拒绝!
这样才能保证插入数据库中的信息的合法性,符合实际需要;
这不唯一键的概念不就出来了:
eg:
设计一个带有唯一键的表:
插入数据:
上面的都是正常插入,接下来我们来试一试各种错误插入:
有了唯一键我们就能保证插入数据库中的合法性和显示性了!
注意:
唯一键如果不设置not null的话是可以插入null值的,null值不参与运算:
外键
语法:
foreign key (字段名) references 主表(列)
外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或唯一键约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
举个例子:
现在上面两张独立表结构,表中已经存在了一定的数据;
好,现在假设来了一个新同学,这个新同学的信息如下(102,“王五”,10);
然后的话我们就要把这个同学的信息保存进学生表中这个没问题,
好,现在又来了一个同学,这个同学的信息如下(103,“赵六”,30)
然后我们也按照流程将这个同学的信息插入进学生表中,可是不对啊,这个学生所属班级是30班,我们这个学校里面没有30班啊!我们学校只有10班、20班啊!这个学生的信息有误啊,我们不应该将这个学生的信息插入进学生表啊!当我们将这名学生的信息插入进学身表的是否数据库应该报错啊!可是实际上数据库允许你插入,并且什么也不告诉你,这就有点扯了!
然后现在又来了一个同学,这个同学的基本信息如下(104,“田七”,null),这个同学是我们学校的但是还暂时未给他分配班级,所以班级一栏暂时为null,因此我们按照流程将数据插入进学生表中,这没问题!
可是啊某一天这个学校快不行了,办的不咋样,于是他就像关闭一个班级!就比如20班吧!于是他就去学校的班级表数据库里面哐呲哐呲删除了班级号为20的班级的所有信息,可是某一天新老师在维护学生表数据库的是否发现李四同学属于我们学校的20班,可是这个新老师会认为我们学校没有20班啊,是不是录学生信息的时候把学生信息录错了,于是它哐呲哐呲的就将李四同学的基本信息从学生表中删除了,这就导致李四同学一下成为的学校黑户!而我们可怜的李四同学什么也没做,无缘无故就成了黑户…这不扯吗!要是当初那个在班级表中删除20号班级的人能够检查一下学生表中是否还有20号班级的学生的话就不会出现这种情况了;
实际上说白了,还是审核的问题,要是在向学生表中添加数据时考虑一下班级表,而删除班级表中的数据时考虑一下生表,就不会出现上面所说的问题了!
而外键约束的出现就是来帮我们自动审核这一关系的!
想要形成外键约束,那么就必须在多个表之间找到公共的字段,也就是能够将多张表联系起来的字段,这个公共字段在主表中必须时唯一的(可以是主键、也可以时唯一键),在从表中可以不是唯一的,像以上这样在从表中的公共字段就叫做外键!而这多个表之间的联系和束缚就叫做外键约束!
从表中的外键数据在插入时会先考虑在主表中该外键数据是否存在;
而主表在删除数据时,也会考虑从表中是否还存在要删除的外键数据!
以上面的例子为例:
学生表和班级表的公共字段就是班级号,因此再根据实际应用场景,可以考虑将班级表设计为主表,学生表设计为从表:
现在分别向两张表里面插入一点数据:
现在我我们再在学生表中插入一个(103,“王五”,20)的数据:
插入成功…
接着插入一个(104,“赵六”,40)的学生信息:
直接报错!
再插入一个(105,“田七”,null)的学生信息:
插入成功!
现在我们再来班级表中删除一下30号班级:
报错!
那如果我先在学生表中将30班的学生的数据全部删光呢?
如何理解外键约束:
首先我们承认,这个世界是数据很多都是相关性的。
理论上,上面的例子,我们不创建外键约束,就正常建立学生表,以及班级表,该有的字段我们都有。
此时,在实际使用的时候,可能会出现什么问题?
有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中?
比如新东方只开了新东方100班,新东方101班,但是在上课的学生里面竟然有新东方102班的学生(这个班目前并不存在),这很明显是有问题的。
因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题。
解决方案就是通过外键完成的。建立外键的本质其实就是把相关性交给mysql去审核了,提前告诉mysql表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入;