MySQL表的约束

目录

前言

一、空属性

二、默认值

三、列描述

四、zerofill

五、主键

六、自增长

七、唯一键

八、外键


前言

本篇是mysql中表的相关约束部分!

真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。这就是表的约束由来

表中一定要有各种的约束,通过约束让我们未来插入数据库表中的数据是符合预期的!!约束的本质是通过技术手段,倒逼程序员插入正确的数据,反之,站在mysql视角,凡是插进来的数据,都是符合数据约束的------约束的最终目标是保证数据的完整性和可预期性

一、空属性

  • 两个值:null(默认的)和not null(不为空)

  • 数据库默认字段基本都是允许为空的,但在实际开发中我们要尽可能保证字段不为空,因为空值无法参与运算。

如果要让某个字段不允许为空,在创建表的时候就可以给对应字段设置 not null 属性。

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

站在正常的业务逻辑中:

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

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

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

sql 复制代码
create table if not exists myclass(
     class_name varchar(20) not null,
     class_room varchar(20) not null,
     other varchar(20)
);

我们查看创建该表的详细 SQL 语句:

可以看到的是前两个字段我们设置了not null,那么在这里就会显示出来,表示我们是必须插入具体值得;而我们的这个other字段是没有设置not null的,默认是 null 的,所以这里后面跟的是default null,表示你想插就插,不插这一类就给默认值null。

我们可以做一下实验验证:

所以说,如果某列设置了not null

  • 必须要插具体值

  • 不插因为后面没有默认值就报错

  • 插入null也报错

如果设置为默认null,可以不插用的是后面带的默认值。

二、默认值

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

  • 如果某一个字段会经常性的出现某个值,那么就可以考虑将这个值设置成该字段的默认值

  • 向表中插入数据时如果不给带有默认值的字段赋值,那么就会使用默认值进行插入

可以说默认值的目的就是为了可以简化数据插入操作,提高数据一致性。

sql 复制代码
create table if not exists student(
     name varchar(12) not null,
     age tinyint unsigned default 20,
     gender varchar(10) default '男'
);

在此表中,age 默认值为20,gender默认值为"男";当插入数据时,如未指定这些列的值,将使用默认值,如下:

总结:default 和 not nul 并不冲突,而是互相补充的。

  • 当用户指明这一列要插的时候,受 null 和 not null 约束,要么插null ,要么插合法数据;总之用户指明这一列要插 ,not null 来约束

  • 当用户忽略这一列的时候,如果设置了默认值使用默认值,如果没有就直接报错;总之用户忽略这一列要插, default 来约束

如果建表的时候, 不给某一列添加任何约束,我们会发现MySQL会对 sql语句 优化,默认会带上default null。所以不插入的时候在表示会显示null。

三、列描述

  • comment:用于给列添加注释说明,便于程序员和数据库管理员理解字段用途。

  • 该属性不会对数据插入产生约束效果。

sql 复制代码
create table if not exists t10(
     name varchar(12) not null comment '用户的用户名',
     age tinyint unsigned default 20 comment '用户的年龄'
);

可以得知的是通过desc查看不到注释信息,但是通过show查看创建该表的详细 SQL 语句时可以看到注释信息

四、zerofill

  • zerofill:在数字前补零,使显示字符长度符合指定的位数。

  • 数据库存储的 数值不变,仅用于展示效果。

sql 复制代码
create table if not exists t11(
    a int unsigned not null,
    b int unsigned zerofill not null
);

这个 int(10) unsigned zerofill 的 10 意味着什么呢?请看下图

我们会发现,zerofill 还是挺形象的,格式就是填满0,这就是zerofill属性的作用,如果宽度小于设定的宽度(这里设置的是10),自动填充0。要注意的是,这只是最后显示的结果,在MySQL中实际存储的还是1 ------如果以后你想显示出的是001,002就可以设置zerofill(用来控制不够的位数补全)。

这里其实有个小细节,为什么我们默认 int() 后面带的是 10 ?更准确的是为什么 unsigned int() 是10,int() 是11?

int占4个字节,有符号取值范围 -2^31 - 2^31-1,无符号取值范围 2^32-1,无论是 2^31,还是 2^32 转成10进制是21亿多,42亿多,这么大的数字其实最后表示处理也就是10位,8位千万,9位亿,10位十亿。用10就可以把所有整数数据位全都表示出来;而 int 多出一个1是因为它是有符号的,多一位标识符号位。

五、主键

主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型

  • primary key:用于标识表中的唯一记录,不允许重复或为空。

  • 表中最多只能有一个主键列。

  • 主键可以通过复合主键的方式使用多列联合唯一标识。

sql 复制代码
create table if not exists t12(
    id int unsigned primary key,
    name varchar(20) not null
);

在此示例中,id 被设为主键,数据库自动为主键列添加 not null 约束。

  • 主键约束对于程序员来讲,未来想往这个表里面插对应插入的数据主键列不能冲突,一旦冲突不让你插入,所以倒逼程序员插的时候尽量不要出现主键冲突。

  • 其次站在 mysql视角 凡是插入这个表里面的数据主键一定是不冲突的。这样的好处是根据主键绝对能拿出来确定的一条记录!------可以保证其唯一性

  • 有了主键可以有针对性的对数据进行增删查改

    比如说更新:

创建主键有两种方法:

  • 创建表的时候就把主键设置好

  • 表建好之和但没有主键,可以追加主键

其次删除 | 添加 主键的SQL 语句都是通过alter来进行的

复合主键

  • 虽然一张表中最多只能有一个主键,但是并不意味着一个表中的主键只能添加给一列!

  • 也就是说一个主键可以被添加到一列,或者多列上。

  • 一个主键被添加到多列上的数据我们就叫做复合主键

在创建表的时候,在所有字段之后,使用 primary key(主键字段列表) 来创建主键,如果有多个字段作为主键,可以使用复合主键。

下面我们就可以用两列合起来当一个主键,如创建一张表让一个学生不能选修同样的课程

sql 复制代码
create table t13(
     id int unsigned,
     course_id int unsigned comment '课程编号',
     score tinyint unsigned comment '课程得分',
     primary key(id,course_id)
     );

可以看到 id 和 course_id 都叫做主键。

因为一位同学可以选修多门课,而一门课又可以被多位同学选,所以我们把 学生id 和 课程id 合为一个主键,这就是复合主键的一个实际运用

  • 换言之,可以选择一列作为主键,也可以选择多列作为主键

  • 但是多个合起来做一个主键,都不一样可以插,有一个不一样可以插,只有多个同时和历史数据一样才会出现主键冲突。 这就是复合主键。

  • 复合主键理解:将多列看成一个整体,全部同时冲突,才会约束

  • 后面可以支持通过主键进行快速查找。

六、自增长

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

就是字段自动增长,从当前最大值加 1,通常配合主键使用,确保值唯一。

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

  • 自增长字段必须是整数

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

sql 复制代码
create table t14(
    id int unsigned primary key auto_increment,
    name varchar(20) not null
);

在此示例中,id 列自增长,无需显式插入,系统自动为其赋值

插入时,我们可以指定插入其他列,id这一列就不管了。可以看到虽然我并没有告诉id要插什么,但是id是自动帮我们插入的,并且是增长的。

和别人不冲突并且连续的,这就是自增长主键。

当我们指定id要插入的时候,也能插进行。然后再插入id相同值的时候,确实能够履行主键的职责发生主键冲突。

自增主键的插入机制

  • 默认行为:自增主键在插入时若未设置任何默认值,则默认从1开始插入。

  • 手动设置起始值:如果手动插入一个新的起始值,且该值大于历史值,则自增主键将从新的起始值开始进行插入。

  • 创建表时,除了在表内设置 auto_increment约束外 ,还可以在表外 设置auto_increment 的值,这代表下一次插入的起始值。

  • 可以使用 last_insert_id() 函数来获取最后一次插入的 AUTO_INCREMENT 值(批量插入获取的是第一个值 )

    sql 复制代码
    select last_insert_id();

关于上面提及的索引:

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

索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的 SQL 语句执行得更快,可快速访问数据库表中的特定信息。

七、唯一键

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

在一张表中,唯一键用于对多个需要唯一性约束的字段进行限制。虽然表中只能有一个主键,但可以使用多个唯一键来确保数据唯一性。

区别:

  • 主键:标识唯一性,主要用于唯一标识记录。

  • 唯一键:更多地用于业务逻辑上的唯一性约束,允许字段为空,并且多个空值不会影响唯一性比较。

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

假设一个场景 (当然,具体可能并不是这样,仅仅为了帮助大家理解)

比如在公司,我们需要一个员工管理系统,系统中有一个员工表,员工表中有两列信息,一个身份证号码,一个是员工工号,我们可以选择身份号码作为主键。

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

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

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

当然,离我们近一些的例子就是:一个学生信息表中有学号,姓名和手机号三个字段,那么我们设置学号为主键之后,这个手机号由于每个人都应该是不一样的手机号,所以应该也给其设置一下唯一键

案例:

sql 复制代码
mysql> create table student (
    -> id char(10) unique comment '学号,不能重复,但可以为空',
    -> name varchar(10)
    -> );
 
mysql> insert into student(id, name) values('01', 'aaa');
mysql> insert into student(id, name) values('01', 'bbb'); -- 触发唯一约束错误
ERROR 1062 (23000): Duplicate entry '01' for key 'id'
 
mysql> insert into student(id, name) values(null, 'bbb'); -- 允许为空

设置唯一键时加了一个unique来约束

唯一键和主键不冲突,可以理解为对主键的补充设置,并且只能有一个主键,但可以有多个唯一键

八、外键

对于外键,我们主要理解两个内容:

  • 从表和主表的关联关系

  • 产生外键约束

外键用于确保表间数据的一致性,例如防止插入一个不存在班级的学生或删除一个还有学生的班级。

  • 定义:外键约束用于建立主表和从表之间的关联关系,主要定义在从表上,主表必须包含主键或唯一键。

外键用于定义主表和从表之间的关系:

  • 外键约束主要定义在从表上

  • 主表则必须是有主键约束或unique约束

  • 当定义外键后,要求外键列数据必须在主表的主键列存在或为NULL

设置外键约束SQL语句:

sql 复制代码
foreign key (字段名) references 主表(列)

案例:

sql 复制代码
-- 主键表:班级表
create table class (
    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 class(id)
);
 
-- 插入班级数据
mysql> insert into class values(10, '高三(9)班'),(20, '高三(19)班');
 
-- 插入学生数据
mysql> insert into stu values(100, '张三', 10), (101, '李四', 20);
 
-- 插入无效班级号的数据,触发外键约束错误
mysql> insert into stu values(102, '王五', 30); -- 无效插入
复制代码

\^\]: 可以看到,并不存在 id为3的班级 可以这么理解外键约束:通过外键约束将表间关系交由数据库管理,避免在业务上关联的表间出现不一致的数据。 ![image-20251019105350582](https://i-blog.csdnimg.cn/img_convert/b257ec56563ece511ef0cf3ec1141b76.png)

相关推荐
UCoding2 小时前
我们来学mysql -- ReadView工作原理
数据库·mysql·readview工作原理
angushine2 小时前
解决MySQL慢日志输出问题
android·数据库·mysql
合作小小程序员小小店2 小时前
网页开发,在线%旧版本旅游管理%系统,基于eclipse,html,css,jquery,servlet,jsp,mysql数据库
java·数据库·servlet·eclipse·jdk·旅游·jsp
core5122 小时前
不借助框架实现Text2SQL
sql·mysql·ai·大模型·qwen·text2sql
q***46522 小时前
Spring Boot 实战:轻松实现文件上传与下载功能
java·数据库·spring boot
2501_941803622 小时前
互联网技术的未来趋势与发展方向:AI、5G与云计算的深度融合
mysql
腾讯云数据库3 小时前
「腾讯云 NoSQL 技术」之 Redis 篇|揭晓腾讯云Redis水平扩缩容极致流畅背后的技术玄机
数据库
SelectDB3 小时前
压缩率提升 48%,详解 Apache Doris 存储压缩优化之道|Deep Dive
数据库·开源·github
DBA圈小圈3 小时前
【KingbaseES】批量修改数据库模式、表等对象的 Owner
数据库·oracle