【MySQL】约束

一、基本概念

1、什么是约束
约束是表级强制规定

2、为什么使用约束
是为了保证表中数据的完整性,完整性又可以拆分为精确性和可靠性

3、怎么去保证数据完整性呢,从以下四个角度进行考虑

  • 实体完整性:一张表中,不能存在两条完全相同无法区分的记录
  • 域完整性:限制某一个字段,例如性别只能是男/女,但是他不会约束年龄
  • 引用完整性:例如员工所在的部门,要在部门表中能找到这个部门的信息
  • 用户自定义完整性:例如用户名唯一、密码不能为空等

4、约束的分类

  • 从约束字段的个数来看:分为单列约束、多列约束
  • 从约束的作用范围来看:分为列级约束(声明在对应字段的后面)、表级约束(表中所有字段都声明完后,在所有字段后单独声明的约束)
  • 从约束的功能上来看
    • not null:非空约束
    • unique:唯一性约束
    • primary key:主键约束
    • foreign key:外键约束
    • check:检查约束
    • default:默认值约束

5、如何添加约束

  • 在CREATE TABLE时添加约束
  • 使用ALTER TABLE添加约束,也可以使用这个删除约束

6、如何查看约束
需要到information_schema``这个库下,查询TABLE_CONSTRAINTS这个表
例如我需要查询t_decade_test表中存在哪些约束,就可以使用

SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE table_name = 't_decade_test';

二、约束类型介绍

1、not null:非空约束

  • 作用:限制某个字段/某列的值不允许为空
  • 关键字:NOT NULL
  • 注意:
    • 空字符串不等于null,0也不等于null
    • 如果没有使用not null约束,那么默认情况下所有的类型都是可以为null的
    • 非空约束只能设置成列级约束

1)如何在建表时创建非空约束

CREATE TABLE t_decade_test_not_null(
id INT NOT NULL,
last_name VARVHAR(20) NOT NULL,
email VARCHAR(25),
salary DECIMAL(10,2)
);

2)创建完这个表后,如下几种情况会报错

  • 使用insert插入数据,id或者last_name的值为null
  • 使用insert插入数据,没有给id或者last_name字段赋值,且没有指定它的默认值
  • 只用update更新数据,给id或者last_name字段传递的值为null

3)如何使用ALTER TABLE添加约束,我们还是以之前的t_decade_test_not_null为例
对email字段添加一个非空约束,但是如果email字段已经存在null值,那么下方的语句是无法执行的

ALTER TABLE t_decade_test_not_null
MODIFY email VARCHAR(25) NOT NULL;

4)如何使用ALTER TABLE删除约束呢?其实只要把NOT NULL改成NULL即可

ALTER TABLE t_decade_test_not_null
MODIFY email VARCHAR(25) NULL;

2、unique:唯一性约束

  • 作用:确保某一列/某一个字段的值不会重复
  • 关键字:UNIQUE
  • 注意点:
    • MySQL会给唯一约束的列上默认建一个唯一索引
    • 一个表中可以设置多个唯一性约束
    • 唯一性约束可以针对某一个字段,也可以针对某几个字段组合起来的值
    • 唯一性约束允许字段为空。如果两条数据,该字段都赋值null,不会受到唯一性约束的限制
    • 创建唯一性约束的时候,如果不给约束命名,那就默认唯一性约束的名字和字段名相同

1)如何在建表时,给字段添加唯一性约束

CREATE TABLE t_decade_test_unique(
id INT UNIQUE #这就是列级约束,
last_name VARVHAR(20),
email VARCHAR(25),
salary DECIMAL(10,2),
# 添加表级约束,一般约束的命名格式为:作用_表名_字段
CONSTRAINT uk_t_decade_test_unique_email UNIQUE(email)
);

2)如何使用ALTER TABLE来添加约束
方式一:alter table 表名 add UNIQUE(字段名称)

alter table t_decade_test_unique add UNIQUE(lastname);# 如果要给约束取名,还是使用constraint
alter table t_decade_test_unique add constraint uk_t_decade_test_unique_lastname UNIQUE(lastname,email);

方式二:alter table 表名 modify 字段名 字段类型 UNIQUE

alter table t_decade_test_unique MODIFY last_name VARVHAR(20) UNIQUE;

3)什么是复合的唯一性约束
可以理解为,我们对多个字段进行组合
要求两条数据中,这几个字段的值不能完全相同,必须有一个或者几个字段的值不一样

CREATE TABLE t_unique_user(
id INT,
user_name VARCHAR(20),
user_pwd VARCHAR(15),
constraint uk_t_unique_user_nameAndPwd UNIQUE(user_name,user_pwd);
);

这样一来,这个表中的任意两条数据,name和pwd字段就不能完全相同

4)删除唯一性约束

  • 创建唯一性约束的字段会自动创建一个唯一索引,所以我们只能通过删除唯一索引的方式来删除该约束
  • 唯一索引的名和唯一性约束的名称是一样的
  • 如果是单列约束,那默认就和字段名称相同,如果是复合约束,那默认就和()中排在第一位的字段名相同。当然我们也可以使用constraint来自定义约束名
alter table t_unique_user
DROP index 索引名;

我们也可以通过show index from 表名;查看表的索引

3、primary key:主键约束

  • 作用:用来标识表中的一行记录,也就是说,可以通过这个来确定某条数据是独一无二的
  • 关键字:primary key
  • 特点:主键约束相当于唯一性约束+非空约束
  • 注意点:
    • 一个表中只能有一个主键约束,它可以在列级别创建,也可以在表级别创建
    • 主键约束对应着表中的一列或者多列(复合主键)
    • 如果是多列组合的复合主键约束,那么任何一列都不允许为空,而且组合的值不允许重复
    • 主键约束的名总是PRIMARY,它不能像前面的唯一性约束一样自定义名称
    • 创建主键约束后,系统会自动在对应的列或者组合字段上创建主键索引(根据主键进行查询的效率更高),如果删除了主键约束,对应的主键索引也会被删除
    • 不要修改主键字段的值,因为他是数据记录的唯一标识,如果修改了主键的值,就有可能破坏数据的完整性

1)创建表时,如何添加主键约束
列级约束

CREATE TABLE t_test_primary_key(
id INT PRIMARY KEY,
last_name VARCHAR(20),
salary DECIMAL(10,2),
email VARCHAR(15)
);

或者表级约束

CREATE TABLE t_test_primary_key(
id INT,
last_name VARCHAR(20),
salary DECIMAL(10,2),
email VARCHAR(15),
constraint prk_t_test_primary_key_id PRIMARY KEY(id) #这里的名称是无效的
);

或者复合主键

CREATE TABLE t_test_table(
id INT,
user_name VARCHAR(20),
user_pwd VARCHAR(15),
PRIMARY KEY(user_name,user_pwd)
);

2)使用ALTER TABLE创建主键约束

ALTER TABLE table_name
ADD PRIMARY KEY (column_name);

3)删除主键约束

ALTER TABLE table_name
DROP PRIMARY KEY;

4、auto_increment:自增列

  • 作用:让某个字段的值自增
  • 特点:
    • 一个表只能有一个自增字段
    • 当需要产生唯一标识符或者顺序值的时候,可以设置自增长
    • 自增长约束的列必须是键列(必须要有主键约束或者唯一性约束),而且自增长约束的列必须是整数类型,在没有给第一条数据的该字段显式赋值情况下,默认从1开始
    • 如果我们在插入某条数据时,自增列对应的value填的是0或者null,实际上入表的值会是该字段当前最大值加1,并不会展示为0或者null

1)在建表时声明自增列

CREATE TABLE t_auto_increment(
id INT PRIMARY KEY AUTO_INCREMENT
last_name VARCHAR(20)
);

2)使用alter table声明自增列

ALTER TABLE t_auto_increment
MODIFY id INT AUTO_INCREMENT;

3)删除自增

ALTER TABLE t_auto_increment
MODIFY id INT;

4)MySQL5.7与MySQL8.0中计数器的差别
假设现在有一个场景,我们连续执行三次insert语句,id字段value都是0
使用select语句后,我们可以发现三条数据的id依次为1,2,3

现在我们同时在两个版本的MySQL中删除id为3的数据
然后重复执行insert id为0这个操作
然后可以发现,两个版本的MySQL中,该表中的第三条数据并不是从3开始了,而是从4开始

然后,我们删除id为4的这条数据,再对两个版本的MySQL服务都进行重启操作,继续重新insert id=0这个操作,我们可以发现

  • MySQL5.7中,该表第三条数据的id重新从3开始
  • MySQL8.0中,该表第三条数据的id从5开始

MySQL5.7中,自增主键的计数器是在内存中维护的,数据库重启后,计数器会被初始化
MySQL8.0中,自增主键的计数器会被持久化到重做日志中,每次计数器发生改变都会记录到该日志中,当数据库重启,InnoDB会根据重做日志来初始化计数器的内存值

5、FOREIGN KEY:外键约束

  • 作用:限制某个表的某个字段的引用完整性,比如说员工表中某个员工的部门id,必须要在部门表中存在
  • 关键字:FOREIGN KEY
  • 了解什么是主表/从表或者说什么是父表/子表:
    • 主表(父表):被引用的表,比如上面的部门表
    • 从表(子表):引用别人的表,比如上面的员工表
  • 特点:
    • 从表的外键引用/参考的必须是主表的主键列或者是唯一约束的那个字段,这是因为被依赖/被参考的值必须是唯一的
    • 创建外键约束时,如果没有自定义名称,那么会自动生成一个外键名,不会像之前介绍的约束一样和列名保持一致了
    • 如果在创建表的时候就指定外键约束,那么必须先创建主表,再创建从表
    • 删表时,先删从表(或者先删外键约束),再删主表
    • 当主表的数据被从表参照时,主表的数据将不被允许删除,如果要删除数据,需要先去从表中删除依赖该记录的数据,然后再删除主表数据
    • 在从表中指定外键约束,一个表可以建立多个外键约束
    • 从表的外键列和主表中被引用的列不一定要名称相同,但是数据类型必须保持一致
    • 创建外键约束时,系统会默认在所在的列上建立普通索引,索引名=列名(列名≠外键约束名)
    • 删除外键约束后,必须手动删除对应的索引

1)在create table时指定外键约束

CREATE TABLE t_dept(
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(20)
);CREATE TABLE t_emp(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20),
department_id INT,
# 使用表级约束的方式指定外键约束
constraint fk_emp_department_id FOREIGN KEY (department_id) REFERENCES t_dept (dept_id)
);

2)演示外键效果
在创建了t_dept和t_emp表之后
如果两张表都是空表,当我们直接执行insert into t_emp values(1,"decade",10);
SQL执行会报错,因为我们从表t_emp依赖的主表t_dept中并没有id为10的记录

所以我们要先执行
insert into t_dept values(10,"技术部");
再执行insert into t_emp values(1,"decade",10);

执行上述插入语句之后
假设我们执行delete from t_dept where id = 10;,语句还是会报错,因为这条数据被从表依赖
同样的,当我们执行update t_dept set id = 20 where dept_name = '技术部';时,语句也会报错

3)建表后如何使用alter table添加外键约束

CREATE TABLE t_dept2(
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(20)
);CREATE TABLE t_emp2(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20),
department_id INT
);ALTER TABLE t_emp2
ADD CONSTRAINT fk_emp2_department_id FOREIGN KEY (department_id) REFERENCES t_dept2 (dept_id);

4)外键约束的约束等级

  • Cascade方式:当父表的数据发生update/delete时,同步update/delete子表中引用此记录的数据
  • Set null方式:当父表的数据发生update/delete时,将子表中引用此记录的外键列设置为null,注意,子表的外键列不允许有非空约束
  • No action方式:如果子表中有引用父表记录的数据,那么不允许对父表对应候选键进行update/delete操作
  • Restrict方式:同No action方式
  • Set default方式:父表有变更时,将子表的外键列设置成一个默认值,但InnoDB不能识别

对于外键约束,最好使用ON UPDATE CASCADE ON DELETE RESTRICT的方式
即更新会同步,但是不允许删除,使用方式如下

CREATE TABLE t_dept(
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(20)
);CREATE TABLE t_emp(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20),
department_id INT,
# 使用表级约束的方式指定外键约束
constraint fk_emp_department_id FOREIGN KEY (department_id) REFERENCES t_dept (dept_id) ON UPDATE CASCADE ON DELETE RESTRICT
);

5)删除外键约束

# 第一步:先查看表中的约束名,删除约束
SELECT * FROM information_schema.TABLE_CONSTRAINTS
WHERE table_name = '表名称';ALTER TABLE 从表名
DROP FOREIGN KEY 外键约束名称;# 第二步:查看索引名和删除索引
SHOW INDEX FROM 表名称;ALTER TABLE 从表名 DROP INDEX 索引名;

6)开发场景
阿里开发规范要求,不得使用外键与级联(可以理解为主表数据更新触发从表相应记录更新),外键与级联适合单机低并发场景,不适合分布式、高并发场景,级联可能导致数据库更新风暴,外键影响数据库插入速度,所以一切外键概念都应该在应用层,即Java代码层面进行解决(经典白学~)

6、check:检查约束

  • 作用:检查某个字段的值是否复合要求
  • 关键字:CHECK
  • 说明:MySQL5.7不支持(可以使用,但对数据验证没有任何作用,就算你添加了不符合要求的数据,也不会触发告警),MySQL8.0支持

1)建表时添加

CREATE TABLE t_emp(
id iNT PRIMARY KEY AUTO_INCREMENT
last_name VARCHAR(20),
salary DECIMAL(10,2) CHECK(salary>5000)
);

如果你执行insert into t_emp values(1, "彭于晏", 1500);,语句就会报错

7、default:默认值约束

  • 作用:给某个字段设置默认值,如果在插入数据时没有给该字段显式赋值,那么就赋值为默认值
  • 关键字:DEFAULT

1)在创建表时添加约束

CREATE TABLE t_emp(
id iNT PRIMARY KEY AUTO_INCREMENT
last_name VARCHAR(20),
salary DECIMAL(10,2) DEFAULT 3000
);

如果你执行insert into t_emp values(1, "彭于晏");,那么此条数据对应salary那一列的值就是3000

2)使用ALTER TABLE添加约束

CREATE TABLE t_emp(
id iNT PRIMARY KEY AUTO_INCREMENT
last_name VARCHAR(20),
salary DECIMAL(10,2)
);ALTER TABLE t_emp
MODIFY salary DECIMAL(10,2) DEFAULT 3000;

3)删除约束

ALTER TABLE t_emp
MODIFY salary DECIMAL(10,2);

三、写在最后

很长时间没有更新博客了,最近也不知道在瞎忙什么,后面会慢慢恢复之前的学习状态,人还是要不断学习,才不会被时代抛弃,希望自己这次坚持的久一点,hh~

如有错误,欢迎指正!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/135560.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Power Apps-库组件连接数据表

点击添加数据 可以选择Excel或SharePoint导入 选择右侧边栏中的网站,再选择想要连接的数据表 点击插入,选择布局中的某个库, 选中它可以点击上方的布局,选择想要的样式 右侧选择数据源中的表就将组件与数据表连接起来了 如果想修…

Vite创建React项目,另外一种更加简单的方法

在上一篇blog中一个一个安装依赖dependencies,有没有一步到位的方法呢,有! 参考《React 18 Design Patterns and Best Practices Design, build, and deploy production-ready web applications with React》4th 第一章倒数第二节Vite as a solution有个…

flutter生态一统甜夏 @Android @ios @windowse @macos @linux @Web

(愿景)G o o g l e 中 国flutter生态一统天下(IT) Web Android ios Windowse Macos Linux Google中国https://space.bilibili.com/64169458 https://pub-web.flutter-io.cn 构建 Flutter Web 应用 构建 Flutter Web 应用 - Flutter 中文文档 - Flutter 中文开发者网站 …

Packet Tracer路由器连接终端设备怎么配置?

在Packet Tracer中配置一台路由器和三台终端设备可以帮助你建立一个简单的局域网,以下是配置的基本步骤: 打开Packet Tracer,从左侧设备栏中拖拽一个路由器和三个终端设备到工作区。 连接设备:使用网线将路由器的端口与每台终端设…

vue3+setup 解决:this.$refs引用子组件报错 is not a function

一、如果在父组件中以下四步都没问题的话&#xff0c;再看下面步骤 二、如果父组件引用的是index页面 请在 头部加上以下代码 &#xff08;如果是form页面请忽略这一步&#xff09; <template> <a-modalv-model:visible"visible"title"头部名称&…

python非线性规划

Python中非线性规划通常使用优化库来处理&#xff0c;其中SciPy库是一个流行的选择。SciPy包含了用于非线性规划的优化算法&#xff0c;可以用来解决各种非线性优化问题。下面是一个简单的非线性规划的示例&#xff0c;使用SciPy来最小化一个非线性目标函数&#xff1a; 首先&a…

SpringCloud 微服务全栈体系(十三)

第十一章 分布式搜索引擎 elasticsearch 二、索引库操作 索引库就类似数据库表&#xff0c;mapping 映射就类似表的结构。 我们要向 es 中存储数据&#xff0c;必须先创建“库”和“表”。 1. mapping 映射属性 mapping 是对索引库中文档的约束&#xff0c;常见的 mapping …

SpringDataJpa(二)

三、Spring Data JPA概述 Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架&#xff0c;可使开发者用极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常用功能&#xff0c;且易于扩展&#xff01;学习并使用 Spring D…

汽车标定技术(五)--基于模型开发如何生成完整的A2L文件(1)

1 数据对象的创建 CtrlH打开Model Explorer&#xff0c;在Base workspace中点击工具栏add&#xff0c;出现如下界面&#xff0c; 可以看到Simulink提供了多种数据类型 Matlab Variable&#xff1a;Simulink.Parameter&#xff1a;使用该数据对象表示工程应用中的标定量Simuli…

js:React中使用classnames实现按照条件将类名连接起来

参考文档 https://www.npmjs.com/package/classnameshttps://github.com/JedWatson/classnames 安装 npm install classnames示例 import classNames from "classnames";// 字符串合并 console.log(classNames("foo", "bar")); // foo bar//…

安卓常见设计模式6------代理模式(Kotlin版)

1. W1 是什么&#xff0c;什么是代理模式&#xff1f;​ 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;用于在访问对象之前或之后提供额外的功能或控制。代理模式可以用于各种情况&#xff0c;例如延迟加载、权限控制、日志记录等。​ 2. …

高性能网络编程 - The C10M problem

文章目录 Pre概述回顾C10K实现C10M的挑战思路总结 Pre 高性能网络编程 - The C10K problem 以及 网络编程技术角度的解决思路 概述 在接下来的10年里&#xff0c;因为IPv6协议下每个服务器的潜在连接数都是数以百万级的&#xff0c;单机服务器处理数百万的并发连接&#xff0…

基于单片机智能加湿器控制系统仿真设计

**单片机设计介绍&#xff0c; 698【毕业课设】基于单片机智能加湿器控制系统仿真设计 文章目录 一 概要系统组成总结 二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 单片机智能加湿器控制系统仿真设计介绍 单片机智能加湿器控制系统是一种利用微…

Jakarta-JVM篇

文章目录 一.前言1. 1 JVM-堆常用调参1.2 JVM-方法区常用参数1.3 JVM-codeCache 二.JVM内存结构三. 对象创建四. JVM垃圾回收算法4.1 可达性分析算法4.1.1 对象引用4.1.2 回收方法区. 4.2 分代回收4.3 标记清除4.4 标记复制4.5 标记整理 五.垃圾回收器5.1 根节点枚举5.2 安全点…

umi4 React项目使用icon集合

umi项目中使用icon集合。 icon集合&#xff1a;https://icones.js.org/ 测试使用这个ion .umirc.ts文件 icons:{autoInstall:{iconify-json/ion: true,//自动安装iconify-json/ion},include: [ion:social-windows-outline]&#xff0c;//要使用的必须把icon类名加到include中…

AndroidStudio 运行报错:Invalid keystore format

AndroidStudio 运行报错&#xff1a;Invalid keystore format 把这玩意儿删了重新打开Android Studio运行一下就好了&#xff01;&#xff01;&#xff01;

esxi 6.7下安装黑裙

esxi上创建一个黑裙系统的虚拟机&#xff0c;用来存资料 一、工具 硬件&#xff1a; 工控机&#xff1a;装有esxi6.7系统&#xff08;192.168.100.2&#xff09;&#xff0c;配置&#xff1a;3865U&#xff0c;16G内存&#xff0c;120Gmsata120sata硬盘&#xff0c;6个网口 主…

利用Ansible实现批量Linux服务器安全配置

1.摘要 在上一篇<<初步利用Ansible实现批量服务器自动化管理>>文章中, 我初步实现了通过编写清单和剧本来实现多台服务器的自动化管理,在本章节中, 我将利用Ansible的剧本来实现更实用、更复杂一点的功能, 主要功能包括三个:1.同时在三台服务器中增加IP访问控制,只…

211. 添加与搜索单词 - 数据结构设计

211. 添加与搜索单词 - 数据结构设计 题目-中等难度示例1. 题目-中等难度 请你设计一个数据结构&#xff0c;支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。 实现词典类 WordDictionary &#xff1a; WordDictionary() 初始化词典对象void addWord(word) 将…

杂货铺 | citespace的使用

安装教程 【CiteSpace保姆级教程1】文献综述怎么写&#xff1f; &#x1f4da;数据下载 1. 新建文件夹 2. 数据下载 知网高级检索 数据选中导出 &#xff1a;一次500 导出后重命名为download_xxx.txt&#xff0c;放到input文件里 3. 数据转换 把output里的数据复制到data里…