约束
# 概念
MySQL中的约束(Constraints)是用于限制表中的数据,以保证数据的完整性和准确性。约束可以确保数据符合特定的条件或规则,从而防止无效或不符合要求的数据进入数据库。
MySQL中主要有以下几种约束:
- 主键约束(
PRIMARY KEY
):主键是表中的一个特殊字段,它唯一标识表中的每条记录。一个表只能有一个主键,主键的值必须是唯一的,且不能为NULL。 - 外键约束(
FOREIGN KEY
):外键用于建立两个表之间的关系。一个表中的外键值必须是另一个表的主键值。 - 唯一约束(
UNIQUE
):唯一约束确保表中的某列或某几列的组合的值是唯一的,不允许出现重复的值。 - 非空约束(
NOT NULL
):非空约束确保表中的某列不能有NULL值,即该列必须有值。 - 检查约束(
CHECK
):检查约束用于确保列中的值满足特定的条件。例如,可以确保年龄列的值在0到120之间。 - 默认值约束(
DEFAULT
):默认值约束用于为列设置默认值。如果插入新记录时没有为某个列指定值,那么将使用该列的默认值。
约束可以在创建表时通过CREATE TABLE
语句定义,也可以在表创建后通过ALTER TABLE语句添加。
需要注意的是,约束的具体使用和效果可能会受到MySQL版本和配置的影响,因此在实际使用时,建议查阅相关版本的官方文档以获取最准确的信息。
-- id 自动增长, 主键
-- name 非空 唯一
-- status 默认值
create table test1(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(10) NOT NULL UNIQUE,
age int,
status char(1) DEFAULT 1,
gender char(1)
);
-- 测试
-- 正常插入
insert into test1(name,age,status,gender) values('lv', 23, 2, '男');
-- name 唯一测试
insert into test1(name,age,gender) values('lv', 23, '男');
-- name 非空测试
insert into test1(name,age,gender) values(null, 23, '男');
-- ERROR 1048 (23000): Column 'name' cannot be null
-- ERROR 1062 (23000): Duplicate entry 'lv' for key 'name'
-- 默认值, id 是否 自动增长
insert into test1(name,age,gender) values('lv22', 23, '男');
-- 查询结果
select * from test1;
/**
+----+------+------+--------+--------+
| id | name | age | status | gender |
+----+------+------+--------+--------+
| 1 | lv | 23 | 2 | 男 |
| 3 | lv22 | 23 | 1 | 男 |
+----+------+------+--------+--------+
2 rows in set (0.00 sec)
*/
# 外键约束
在MySQL中,外键约束(FOREIGN KEY
)用于确保一个表中的数据引用另一个表中的主键值。
外键约束是用于维护两个表之间数据一致性和完整性的重要手段。
以下是关于MySQL中外键约束的一些关键点:
定义外键: 外键是在一个表中定义的,它引用了另一个表的主键。外键用于确保引用的数据在父表(被引用的表)中存在。
语法: 当创建新表时,可以在列定义中包含外键约束:
CREATE TABLE 子表名 (
子表字段1 数据类型,
子表字段2 数据类型,
外键字段 数据类型,
CONSTRAINT 外键约束名 FOREIGN KEY (外键字段) REFERENCES 主表名(主键字段)
);
-- 或者
CREATE TABLE 子表名 (
子表字段1 数据类型,
子表字段2 数据类型,
外键字段 数据类型,
FOREIGN KEY (外键字段) REFERENCES 主表名(主键字段)
);
或者在表创建后添加外键约束:
ALTER TABLE 子表名
ADD CONSTRAINT 外键约束名
FOREIGN KEY (外键字段) REFERENCES 主表名(主键字段);
引用: 外键约束引用另一个表的主键(PRIMARY KEY)或唯一键(UNIQUE)。被引用的列在父表中必须是主键或具有唯一约束。
操作限制: 当外键约束存在时,对子表(包含外键的表)的操作会受到限制。例如,您不能插入一个外键值,除非该值在父表的主键列中存在。同样,如果尝试删除或更新父表中的被引用行,并且子表中还有引用该行的数据,那么操作将会失败,除非您设置了适当的级联操作(如ON DELETE CASCADE)。
级联操作: 外键约束可以包含级联操作,指定当父表中的数据被更新或删除时应如何自动处理子表中的相关记录。例如:
ON DELETE CASCADE
:当父表中的行被删除时,子表中所有引用该行的记录也会被删除。
ON UPDATE CASCADE
:当父表中的主键值被更新时,子表中所有引用该值的记录的外键值也会被更新。
禁用和启用外键约束: 在某些情况下,您可能需要暂时禁用外键约束,例如在进行批量数据导入或删除时。您可以使用以下命令来禁用和启用外键约束:
-- 禁用外键约束检查
SET FOREIGN_KEY_CHECKS=0;
-- 执行您的操作,如插入、更新或删除数据
-- 启用外键约束检查
SET FOREIGN_KEY_CHECKS=1;
请注意,禁用外键约束检查可能会破坏数据的完整性,因此应谨慎使用,并在操作完成后尽快恢复外键约束检查。
外键约束是关系型数据库管理系统(RDBMS)中用于保持数据一致性和完整性的重要工具。它们确保了在执行可能破坏引用完整性的操作时,数据库系统能够采取适当的行动来维护数据的一致性。
ALTER TABLE 表名 DROP FOREIGN KEY 外键约束名;
# 外键删除、更新 行为
外键的删除和更新行为是指当主键表(即父表)中的记录被删除或更新时,外键表(即子表)中相应的记录应该如何处理。MySQL支持以下外键删除和更新行为:
CASCADE(级联):
删除: 当在父表中删除对应记录时,子表中所有引用该记录的外键行也会被删除。 更新: 当在父表中更新对应记录时,子表中所有引用该记录的外键行也会被更新。
SET NULL:
删除: 当在父表中删除对应记录时,子表中所有引用该记录的外键值会被设置为NULL(前提是该外键列允许NULL值)。 更新: 当在父表中更新对应记录时,子表中所有引用该记录的外键值会被设置为NULL(前提是该外键列允许NULL值)。
NO ACTION 和 RESTRICT:
删除/更新: 当父表中存在被引用的记录时,不允许删除或更新该记录。这实际上是一种阻止删除或更新操作的约束。
SET DEFAULT:
删除/更新: 设置外键列的值为默认值(但请注意,MySQL的InnoDB存储引擎不支持这种行为)。
在实际应用中,选择哪种行为取决于你的业务需求和数据库设计。例如,如果你想要保持数据的完整性,即使父表的记录被删除,你可能希望使用SET NULL或CASCADE。如果你不希望子表中的数据被更改或删除,那么NO ACTION或RESTRICT可能更合适。
在MySQL中,你可以通过ALTER TABLE语句来添加外键约束,并指定删除和更新行为,如下所示:
ALTER TABLE 子表名
ADD CONSTRAINT 外键约束名
FOREIGN KEY (子表外键字段)
REFERENCES 父表名(父表主键字段)
ON DELETE 行为
ON UPDATE 行为;
其中“行为”可以是CASCADE
, SET NULL
, NO ACTION
, RESTRICT
, 或 SET DEFAULT
。
注意:在定义外键约束时,必须确保父表的主键字段和被引用的子表外键字段具有相同的数据类型和长度,并且父表的主键字段必须有一个主键或唯一索引。
此外,使用外键可能会影响数据库的性能,特别是在进行更新操作时,因为数据库需要执行额外的检查操作来确保引用完整性。此外,外键的使用还可能增加数据库的耦合度,并在某些情况下可能导致热更新后服务不可用。因此,在决定使用外键之前,应该仔细考虑这些因素。
# 数据准备
create table dept(
id int auto_increment comment 'ID' primary key,
name varchar(50) not null comment '部门名称'
)comment '部门表';
INSERT INTO dept (id, name) VALUES (1, '研发部'), (2, '市场部'),(3, '财务部'), (4,'销售部'), (5, '总经办');
create table emp(
id int auto_increment comment 'ID' primary key,
name varchar(50) not null comment '姓名',
age int comment '年龄',
job varchar(20) comment '职位',
salary int comment '薪资',
entrydate date comment '入职时间',
managerid int comment '直属领导ID',
dept_id int comment '部门ID'
)comment '员工表';
INSERT INTO emp (id, name, age, job,salary, entrydate, managerid, dept_id)
VALUES
(1, '金庸', 66, '总裁',20000, '2000-01-01', null,5),(2, '张无忌', 20,'项目经理',12500, '2005-12-05', 1,1),
(3, '杨逍', 33, '开发', 8400,'2000-11-03', 2,1),(4, '韦一笑', 48, '开发',11000, '2002-02-05', 2,1),
(5, '常遇春', 43, '开发',10500, '2004-09-07', 3,1),(6, '小昭', 19, '程序员鼓励师',6600, '2004-10-12', 2,1);