当前位置: 首页 > news >正文

SQL基础⑪ | 约束

0 序言

本文主要围绕数据库约束讲起,涵盖约束的基本概念分类及各类约束(非空、唯一、主键、自增列、外键、CHECK、DEFAULT)的作用、特点、操作方法与示例。

通过学习,可掌握约束的定义逻辑、使用场景及实操技能,理解其在保证数据完整性中的关键作用。

1 约束(constraint)概述

1.1 为什么需要约束

从数据完整性来说,

  • 数据完整性(Data Integrity)指数据的精确性(Accuracy)和可靠性(Reliability),目的是防止数据库中存在不符合语义规定的数据,避免错误信息导致无效操作或错误。

我们可以从四方面保证数据完整性:

  • 实体完整性:如同一表中不能有两条完全相同无法区分的记录。
  • 域完整性:如年龄范围0-120,性别范围“男/女”。
  • 引用完整性:如员工所在部门需在部门表中存在。
  • 用户自定义完整性:如用户名唯一、密码不能为空等。

1.2 什么是约束

约束是表级的强制规定,可在创建表时(通过CREATE TABLE语句)或表创建后(通过ALTER TABLE语句)设置。

1.3 约束的分类

1.3.1 按约束数据列的限制

  • 单列约束:每个约束仅约束一列。
  • 多列约束:每个约束可约束多列数据。

1.3.2 按约束的作用范围

  • 列级约束:作用于单个列,跟在列定义后。
    • 支持的约束类型:语法上都支持,但外键无效果。
    • 是否可起约束名:不可以。
  • 表级约束:作用于多个列,单独定义在所有列下方。
    • 支持的约束类型:默认和非空不支持,其他支持。
    • 是否可起约束名:可以(主键无效果)。

1.3.3 按约束的作用

  • NOT NULL:非空约束,规定字段不能为空。
  • UNIQUE:唯一约束,规定字段在表中唯一。
  • PRIMARY KEY:主键约束(非空且唯一)。
  • FOREIGN KEY:外键约束。
  • CHECK:检查约束。
  • DEFAULT:默认值约束。

1.4 查看表的约束

通过查询系统库信息查看:

SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';

在这里插入图片描述
这里就可以看到表约束详情。

2 非空约束(NOT NULL)

2.1 作用

限定某个字段/列的值不允许为空。
关键字为:NOT NULL

2.2 特点

  • 默认情况下,所有类型的值都可为NULL(包括INT、FLOAT等)。
  • 非空约束仅作用于单个列,一个表可有多列设非空约束。
  • 空字符串’'≠NULL,0≠NULL。

2.3 添加非空约束

2.3.1 建表时添加

CREATE TABLE 表名称(字段名 数据类型,字段名 数据类型 NOT NULL,字段名 数据类型 NOT NULL
);-- 示例
CREATE TABLE emp(NAME VARCHAR(20) NOT NULL,sex CHAR NULL
);CREATE TABLE student(sid INT,sname VARCHAR(20) NOT NULL,tel CHAR(11),cardid CHAR(18) NOT NULL
);
  • 插入数据示例:
-- 成功(所有非空字段均赋值)
INSERT INTO student VALUES(1,'张三','13710011002','110222198912032545');
-- 失败(cardid为NULL,违反非空约束)
INSERT INTO student VALUES(2,'李四','13710011002',NULL);
-- 成功(tel允许为空)
INSERT INTO student VALUES(2,'李四',NULL,'110222198912032546');
-- 失败(sname为NULL,违反非空约束)
INSERT INTO student VALUES(3,NULL,NULL,'110222198912032547');

在这里插入图片描述

可以自己动手试一下,

规则出错会弹出错误信息,

但只要满足建表是设定好的约束条件即可。

2.3.2 建表后添加

ALTER TABLE 表名称 MODIFY 字段名 数据类型 NOT NULL;-- 示例
ALTER TABLE emp MODIFY sex VARCHAR(30) NOT NULL;
ALTER TABLE student MODIFY sname VARCHAR(20) NOT NULL;

这样就可以在已有的表格进行约束添加。

2.4 删除非空约束

-- 方式1:显式指定NULL
ALTER TABLE 表名称 MODIFY 字段名 数据类型 NULL;
-- 方式2:不指定NOT NULL(默认允许为空)
ALTER TABLE 表名称 MODIFY 字段名 数据类型;-- 示例
ALTER TABLE emp MODIFY sex VARCHAR(30) NULL;
ALTER TABLE emp MODIFY NAME VARCHAR(15) DEFAULT 'abc' NULL;

3 唯一约束(UNIQUE)

限制某个字段/列的值在整个表中唯一

这里核心就是唯一,关键字为:UNIQUE

3.1 特点

  • 一个表可有多个唯一约束
  • 可约束单个列或多列组合(复合唯一)。
  • 允许列值为空(可多个NULL)。
  • 未命名时,默认与列名相同(单列)或与组合列中第一个列名相同(多列)。
  • MySQL会为唯一约束列自动创建唯一索引

3.2 添加唯一约束

3.2.1 建表时添加

-- 列级约束方式
CREATE TABLE 表名称(字段名 数据类型,字段名 数据类型 UNIQUE,字段名 数据类型 UNIQUE KEY
);-- 表级约束方式
CREATE TABLE 表名称(字段名 数据类型,字段名 数据类型,字段名 数据类型,CONSTRAINT 约束名 UNIQUE KEY(字段名)
);-- 示例
CREATE TABLE student(sname VARCHAR(20),tel CHAR(11) UNIQUE,cardid CHAR(18) UNIQUE KEY
);CREATE TABLE t_course(cid INT UNIQUE,cname VARCHAR(100) UNIQUE,description VARCHAR(200)
);-- 复合唯一(用户名和密码组合唯一)
CREATE TABLE USER(id INT NOT NULL,NAME VARCHAR(25),PASSWORD VARCHAR(16),CONSTRAINT uk_name_pwd UNIQUE(NAME,PASSWORD)
);
  • 插入数据示例(违反唯一约束):
-- 成功
INSERT INTO student VALUES(1,'张三','13710011002','101223199012015623');
INSERT INTO student VALUES(2,'李四','13710011003','101223199012015624');
-- 失败(cardid重复)
INSERT INTO student VALUES(3,'王五','13710011004','101223199012015624');
-- 失败(tel重复)
INSERT INTO student VALUES(3,'王五','13710011003','101223199012015625');

在这里插入图片描述

后两个语句就会报错,为什么呢?

就是因为它违反了唯一约束,所以系统就会报错。

3.2.2 建表后添加

-- 方式1:表级约束添加
ALTER TABLE 表名称 ADD UNIQUE KEY(字段列表);
-- 方式2:列级约束添加
ALTER TABLE 表名称 MODIFY 字段名 字段类型 UNIQUE;-- 示例
ALTER TABLE USER ADD UNIQUE(NAME,PASSWORD);
ALTER TABLE USER MODIFY NAME VARCHAR(20) UNIQUE;-- 为student表的tel和cardid添加唯一约束
CREATE TABLE student(sid INT PRIMARY KEY,sname VARCHAR(20),tel CHAR(11),cardid CHAR(18)
);
ALTER TABLE student ADD UNIQUE KEY(tel);
ALTER TABLE student ADD UNIQUE KEY(cardid);

同样的道理,就是在已有的表格里添加唯一约束。

3.3 复合唯一约束

  • 多列组合的值唯一,语法:
CREATE TABLE 表名称(字段名 数据类型,字段名 数据类型,字段名 数据类型,UNIQUE KEY(字段列表) -- 字段间用逗号分隔
);-- 示例(选课表:学生ID和课程ID组合唯一,避免重复选课)
CREATE TABLE student(sid INT,sname VARCHAR(20),tel CHAR(11) UNIQUE KEY,cardid CHAR(18) UNIQUE KEY
);CREATE TABLE course(cid INT,cname VARCHAR(20)
);CREATE TABLE student_course(id INT,sid INT,cid INT,score INT,UNIQUE KEY(sid,cid) -- 复合唯一
);-- 插入数据
INSERT INTO student VALUES(1,'张三','13710011002','101223199012015623');
INSERT INTO student VALUES(2,'李四','13710011003','101223199012015624');
INSERT INTO course VALUES(1001,'Java'),(1002,'MySQL');
INSERT INTO student_course VALUES(1,1,1001,89),(2,1,1002,90),(3,2,1001,88),(4,2,1002,56);-- 失败(sid=1和cid=1001的组合已存在)
INSERT INTO student_course VALUES(5,1,1001,88);

在这里插入图片描述

在这里插入图片描述

3.4 删除唯一约束

  • 需通过删除唯一索引实现,步骤:
-- 1. 查看约束名
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名';
-- 2. 删除唯一索引(索引名即约束名)
ALTER TABLE 表名称 DROP INDEX 约束名;-- 示例
ALTER TABLE USER DROP INDEX uk_name_pwd;-- 查看表索引(辅助确认)
SHOW INDEX FROM 表名称;

在这里插入图片描述
比如说这张图片,就能看到具体的约束了。

再比如说,我现在想要删除tel这个约束,

在这里插入图片描述

运行程序后,

在这里插入图片描述

4 主键约束(PRIMARY KEY)

唯一标识表中的一行记录。

关键字为:PRIMARY KEY

4.1 特点

  • 相当于唯一约束+非空约束:不允许重复,不允许为空。
  • 一个表最多只能有一个主键约束(可单列或多列组合)。
  • 复合主键:多列组合唯一,且各列均不允许为空。
  • MySQL主键名固定为PRIMARY,自定义名称无效。
  • 系统会为-primary key约束列创建主键索引,删除主键约束时索引自动删除。
  • 不建议修改主键值,可能破坏数据完整性

4.2 添加主键约束

4.2.1 建表时添加

-- 列级约束方式
CREATE TABLE 表名称(字段名 数据类型 PRIMARY KEY,字段名 数据类型
);-- 表级约束方式
CREATE TABLE 表名称(字段名 数据类型,字段名 数据类型,CONSTRAINT 约束名 PRIMARY KEY(字段名)
);-- 示例
CREATE TABLE temp(id INT PRIMARY KEY,name VARCHAR(20)
);-- 列级约束+自增
CREATE TABLE emp4(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20)
);-- 表级约束示例
CREATE TABLE emp5(id INT NOT NULL AUTO_INCREMENT,NAME VARCHAR(20),pwd VARCHAR(15),CONSTRAINT emp5_id_pk PRIMARY KEY(id)
);
  • 插入数据示例(违反主键约束):
-- 成功
INSERT INTO temp VALUES(1,'张三'),(2,'李四');
-- 失败(id=1重复)
INSERT INTO temp VALUES(1,'王五');
-- 失败(id为NULL)
INSERT INTO temp VALUES(NULL,'李琦');

4.2.2 建表后添加

ALTER TABLE 表名称 ADD PRIMARY KEY(字段列表); -- 字段列表可为单列或多列(复合主键)-- 示例
ALTER TABLE emp5 ADD PRIMARY KEY(NAME,pwd); -- 复合主键

4.3 复合主键

  • 多列组合唯一标识记录,语法:
CREATE TABLE 表名称(字段名 数据类型,字段名 数据类型,字段名 数据类型,PRIMARY KEY(字段名1,字段名2)
);-- 示例(选课表:sid和cid组合为主键)
CREATE TABLE student(sid INT PRIMARY KEY,sname VARCHAR(20)
);CREATE TABLE course(cid INT PRIMARY KEY,cname VARCHAR(20)
);CREATE TABLE student_course(sid INT,cid INT,score INT,PRIMARY KEY(sid,cid) -- 复合主键
);-- 插入数据
INSERT INTO student VALUES(1,'张三'),(2,'李四');
INSERT INTO course VALUES(1001,'Java'),(1002,'MySQL');
INSERT INTO student_course VALUES(1,1001,89),(1,1002,90),(2,1001,88),(2,1002,56);-- 失败(sid=1和cid=1001的组合已存在)
INSERT INTO student_course VALUES(1,1001,100);

道理相同,

这里就不重复演示了。

4.4 删除主键约束

ALTER TABLE 表名称 DROP PRIMARY KEY;-- 示例
ALTER TABLE student DROP PRIMARY KEY;
ALTER TABLE emp5 DROP PRIMARY KEY;

这里要注意,删除后,非空约束可能仍存在(若原主键列有非空设置)。

5 自增列(AUTO_INCREMENT)

使某个字段的值自动递增。

关键字为:AUTO_INCREMENT

5.1 特点和要求

  • 一个表最多一个自增列
  • 自增列必须是键列(主键或唯一键)。
  • 数据类型必须为整数类型。
  • 若指定0或NULL,值为当前最大值+1;手动指定具体值则直接赋值。

5.2 添加自增约束

5.2.1 建表时添加

CREATE TABLE 表名称(字段名 数据类型 PRIMARY KEY AUTO_INCREMENT,字段名 数据类型 UNIQUE KEY NOT NULL,字段名 数据类型 UNIQUE KEY,字段名 数据类型 NOT NULL DEFAULT 默认值
);-- 示例
CREATE TABLE employee(eid INT PRIMARY KEY AUTO_INCREMENT,ename VARCHAR(20)
);

5.2.2 建表后添加

ALTER TABLE 表名称 MODIFY 字段名 数据类型 AUTO_INCREMENT;-- 示例
CREATE TABLE employee(eid INT PRIMARY KEY,ename VARCHAR(20)
);
ALTER TABLE employee MODIFY eid INT AUTO_INCREMENT;

5.3 删除自增约束

ALTER TABLE 表名称 MODIFY 字段名 数据类型; -- 移除AUTO_INCREMENT-- 示例
ALTER TABLE employee MODIFY eid INT;

5.4 MySQL 8.0特有-自增变量的持久化

  • MySQL 5.7及之前:自增主键值若大于max(primary key)+1,重启后会重置为max(primary key)+1,可能导致冲突。
  • MySQL 8.0:将自增计数器持久化到重做日志,重启后根据日志初始化,避免重置。
  • 示例(MySQL 5.7与8.0对比):
-- 创建表
CREATE TABLE test1(id INT PRIMARY KEY AUTO_INCREMENT);
-- 插入数据
INSERT INTO test1 VALUES(0),(0),(0),(0); -- id为1,2,3,4
DELETE FROM test1 WHERE id=4; -- 删除id=4
INSERT INTO test1 VALUES(0); -- MySQL 5.7: id=5;8.0: id=5
DELETE FROM test1 WHERE id=5;
-- 重启数据库后插入
INSERT INTO test1 VALUES(0); -- MySQL 5.7: id=4;8.0: id=6

从这里对比可以看出,

MySQL 5.7 与 8.0 自增主键机制是不相同的,

5.7 中自增计数器存内存,重启后重置为表最大主键 +1,可能致主键不连续、引发冲突;

8.0 则将其持久化到重做日志,重启恢复状态保连续性。

6 外键约束(FOREIGN KEY)

保证某个表的字段引用的完整性(如员工部门需在部门表中存在)。

关键字为FOREIGN KEY

6.1 主表和从表(父表和子表)

  • 主表(父表):被引用的表。
  • 从表(子表):引用主表的表。

比如说,部门表是主表,员工表是从表;学生表和课程表是主表,选课表是从表。

6.2 特点

  • 从表外键列必须引用主表的主键唯一约束列(被引用值需唯一)。
  • 未命名时,默认生成外键名(如student_ibfk_1),可自定义。
  • 创建顺序先主表,后从表
  • 删除顺序先从表(或先删外键约束),后主表
  • 主表记录被从表引用时,不可直接删除(需先删从表依赖数据)。
  • 一个表可建立多个外键约束
  • 从表外键列与主表被引用列名可不同,但数据类型和逻辑意义必须一致。

6.3 添加外键约束

6.3.1 建表时添加

-- 创建主表
CREATE TABLE 主表名称(字段1 数据类型 PRIMARY KEY,字段2 数据类型
);-- 创建从表(含外键)
CREATE TABLE 从表名称(字段1 数据类型 PRIMARY KEY,字段2 数据类型,CONSTRAINT 外键约束名 FOREIGN KEY(从表字段) REFERENCES 主表名(主表字段)
);-- 示例
CREATE TABLE dept( -- 主表did INT PRIMARY KEY, -- 部门编号dname VARCHAR(50) -- 部门名称
);CREATE TABLE emp( -- 从表eid INT PRIMARY KEY, -- 员工编号ename VARCHAR(5), -- 员工姓名deptid INT, -- 部门ID(外键)FOREIGN KEY (deptid) REFERENCES dept(did)
);

6.3.2 建表后添加

ALTER TABLE 从表名 ADD [CONSTRAINT 约束名] FOREIGN KEY(从表字段) REFERENCES 主表名(主表字段) [ON UPDATE 等级] [ON DELETE 等级];-- 示例
ALTER TABLE emp ADD CONSTRAINT emp_dept_id_fk FOREIGN KEY(deptid) REFERENCES dept(did);

6.4 常见错误情况

  • 主表被引用列非键列ERROR 1215 (HY000): Cannot add foreign key constraint
  • 数据类型不一致ERROR 1215 (HY000): Cannot add foreign key constraint
  • 从表插入主表不存在的值ERROR 1452 (23000): ... foreign key constraint fails

6.5 约束等级

  • Cascade:主表更新/删除,从表同步更新/删除匹配记录。
  • Set null:主表更新/删除,从表匹配记录列设为NULL(外键列不能为NOT NULL)。
  • No action/Restrict:若从表有匹配记录,不允许主表更新/删除(默认等级)。
  • Set default:主表变更,从表外键列设为默认值(InnoDB不支持)。
  • 示例(ON UPDATE CASCADE ON DELETE SET NULL):
CREATE TABLE dept(did INT PRIMARY KEY,dname VARCHAR(50)
);CREATE TABLE emp(eid INT PRIMARY KEY,ename VARCHAR(5),deptid INT,FOREIGN KEY (deptid) REFERENCES dept(did) ON UPDATE CASCADE ON DELETE SET NULL
);-- 插入数据
INSERT INTO dept VALUES(1001,'教学部'),(1002,'财务部'),(1003,'咨询部');
INSERT INTO emp VALUES(1,'张三',1001),(2,'李四',1001),(3,'王五',1002);-- 主表更新,从表同步(deptid=1002→1004,emp中王五的deptid变为1004)
UPDATE dept SET did=1004 WHERE did=1002;-- 主表删除,从表设为NULL(删除deptid=1001,emp中张三、李四的deptid变为NULL)
DELETE FROM dept WHERE did=1001;

前面的4 5小结,理解难度不算很高,

思路也比较清晰,

这里的示例我用图片给大家解释一下,

这个理解了,后续的7、8小结理解起来会更清洗,也更容易一些。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.6 删除外键约束

-- 1. 查看外键约束名
SELECT * FROM information_schema.table_constraints WHERE table_name = '从表名';
-- 2. 删除外键约束
ALTER TABLE 从表名 DROP FOREIGN KEY 约束名;
-- 3. 查看索引名(外键自动创建的索引)
SHOW INDEX FROM 从表名;
-- 4. 删除索引
ALTER TABLE 从表名 DROP INDEX 索引名;-- 示例
ALTER TABLE emp DROP FOREIGN KEY emp_ibfk_1;
ALTER TABLE emp DROP INDEX deptid;

6.7 开发场景与规范

  • 非必须建立外键:外键会增加系统开销,高并发场景可能不适用,可在应用层保证数据一致性。

7 CHECK 约束

检查字段值是否符合指定条件(如范围、枚举等)。

关键字为:CHECK

7.1 示例

-- MySQL 8.0有效
CREATE TABLE employee(eid INT,ename VARCHAR(5),gender CHAR CHECK (gender IN ('男','女')) -- 性别只能是男/女
);CREATE TABLE temp(id INT AUTO_INCREMENT,NAME VARCHAR(20),age INT CHECK(age > 20), -- 年龄大于20PRIMARY KEY(id)
);

8 DEFAULT 约束

为字段指定默认值,插入数据时未显式赋值则使用默认值。

关键字为:DEFAULT

8.1 添加默认值约束

8.1.1 建表时添加

CREATE TABLE 表名称(字段名 数据类型 PRIMARY KEY,字段名 数据类型 NOT NULL DEFAULT 默认值,字段名 数据类型 DEFAULT 默认值
);-- 示例
CREATE TABLE employee(eid INT PRIMARY KEY,ename VARCHAR(20) NOT NULL,gender CHAR DEFAULT '男', -- 默认性别为男tel CHAR(11) NOT NULL DEFAULT '' -- 默认电话为空字符串
);

8.1.2 建表后添加

ALTER TABLE 表名称 MODIFY 字段名 数据类型 DEFAULT 默认值;
-- 保留非空约束时
ALTER TABLE 表名称 MODIFY 字段名 数据类型 DEFAULT 默认值 NOT NULL;-- 示例
CREATE TABLE employee(eid INT PRIMARY KEY,ename VARCHAR(20),gender CHAR,tel CHAR(11) NOT NULL
);
-- 为gender添加默认值
ALTER TABLE employee MODIFY gender CHAR DEFAULT '男';
-- 为tel添加默认值并保留非空
ALTER TABLE employee MODIFY tel CHAR(11) DEFAULT '' NOT NULL;

8.2 删除默认值约束

-- 移除DEFAULT,保留非空
ALTER TABLE 表名称 MODIFY 字段名 数据类型 NOT NULL;
-- 移除DEFAULT,允许为空
ALTER TABLE 表名称 MODIFY 字段名 数据类型;-- 示例
ALTER TABLE employee MODIFY gender CHAR; -- 移除gender的默认值
ALTER TABLE employee MODIFY tel CHAR(11) NOT NULL; -- 移除tel的默认值,保留非空

9 小结

本文详细介绍了数据库约束的核心知识,包括约束的定义分类及各类约束(非空、唯一、主键、自增、外键、CHECK、DEFAULT)的操作方法与示例。

约束是保证数据完整性的关键机制,通过合理使用约束,可有效防止无效或错误数据进入数据库

不同约束适用于不同场景,如主键用于唯一标识记录,外键保证引用完整性,默认值简化数据插入

同时,需注意数据库版本差异(如MySQL 8.0自增持久化)及开发规范(如阿里不建议使用外键),在实际应用中灵活选择合适的约束策略。

http://www.xdnf.cn/news/1179505.html

相关文章:

  • 基于ABC与BP神经网络分类模型的特征选择方法研究(Python实现)
  • 制造业新突破:AR 培训系统助力复杂操作轻松上手​
  • Linux服务器安全自动化审计实战:一键扫描账户/网络/进程/计划任务风险(附开源脚本)
  • 数据库期中复习
  • 【Guava】1.1.我的报告
  • 进程调度的艺术:从概念本质到 Linux 内核实现
  • Windows 10 远程桌面(RDP)防暴力破解脚本
  • 用python自动标注word试题选项注意事项
  • 安全逆向工程学习路线
  • 4.1.2 XmlInclude 在 C# 中的作用及示例
  • 【Unity开发】数据存储——XML
  • web:js函数的prototype(原型对象)属性
  • Opentrons 模块化平台与AI技术助力智能移液创新,赋能AAW™自动化工作站
  • 电商项目_秒杀_架构升级
  • YOLOv4深度解析:革命性的实时目标检测技术
  • 报告研读——103页数据资产价值实现研究报告( 2023)【附全文阅读】
  • 【ECharts✨】解决Vue 中 v-show 导致组件 ECharts 样式异常问题
  • PAT 甲级题目讲解:1003《Emergency》
  • Apache Commons:Java开发者的瑞士军刀
  • C语言第四章函数
  • Perf编译和使用
  • kettle插件-kettle数据挖掘ARFF插件
  • 2025年7月23日 AI 今日头条
  • 【已解决】YOLO11模型转wts时报错:PytorchStreamReader failed reading zip archive
  • C++实现精确延时的方法
  • 鸿蒙平台运行Lua脚本
  • 论文阅读:《无约束多目标优化的遗传算法,群体和进化计算》
  • 【Word Press进阶】自定义区块的行为与样式
  • Linux(centos7)安装 docker + ollama+ deepseek-r1:7b + Open WebUI(内含一键安装脚本)
  • Terraform与Ansible的关系