MySQL约束和三大范式
一、约束
1.1.什么是约束?为什么要有约束?
- 为了保证数据的一致性和完整性,SQL规范以约束的方式对表数据进行额外的条件限制。
- 约束是表级别的强制规定
- 可以在创建表时规定约束(通过 CREATE TABLE 语句),或者在表创建之后也可以(通 过 ALTER TABLE 语句)
1.2.MySQL有哪些约束?
有以下六种约束:
- NOT NULL 非空约束,规定某个字段不能为空
- UNIQUE 唯一约束,规定某个字段在整个表中是唯一的
- PRIMARY KEY 主键(非空且唯一)
- FOREIGN KEY 外键
- CHECK 检查约束
- DEFAULT 默认值
注意:MySQL不支持check约束,但可以使用check约束,而没有任何效果; 具体细节可以参阅W3Cschool手册
MySQL 8.0.16 是第一个支持 CHECK 约束的版本。如果使用 MySQL 8.0.15 或更早版本,MySQL 参考手册中明确表示:CHECK 子句会被解析,但被所有存储引擎忽略。如果您想要使用 CHECK 约束,可以尝试使用触发器来实现类似的功能。
1.3.约束分类
根据约束数据列的限制,约束可分为:
- 单列约束:每个约束只约束一列
- 多列约束:每个约束可约束多列数据
根据约束的作用范围,约束可分为:
- 列级约束只能作用在一个列上,跟在列的定义后面
- 表级约束可以作用在多个列上,不与列一起,而是 单独定义
二、NOT NULL 约束
2.1.NOT NULL 约束说明
非空约束用于确保当前列的值不为空值,非空约束只能出现在表对象的列上。
Null类型特征:
- 所有的类型的值都可以是null,包括int、 float等数据类型
- 空字符串””不等于null,0也不等于null
2.2.NOT NULL 约束
创建表时使用not null 约束:
CREATE TABLE emp( id INT(10) NOT NULL, name VARCHAR(20) NOT NULL DEFAULT 'abc', sex CHAR NULL )
增加not null 约束:
ALTER TABLE emp MODIFY sex VARCHAR(30) NOT NULL;
查看表结构:

上面设置为空约束后,插入数据的时候必须要有值才可以,否则会报错如下:

2.3.取消NOT NULL 约束
- 取消 not null 约束:
ALTER TABLE emp MODIFY sex VARCHAR(30) NULL;
查看结构:

- 取消 not null 约束,增加默认值
ALTER TABLE emp MODIFY name VARCHAR(15) DEFAULT 'augus' NULL;
注意:设置默认值后如果插入数据不设置name字段的值,则会使用默认值
二、UNIQUE约束
2.1.UNIQUE约束
同一个表可以有多个唯一约束,多个列组合的约束。 在创建唯一约束的时候,如果不给唯一约束名称,就默认和列名相同。MySQL会给唯一约束的列上默认创建一个唯一索引
# 给name列添加唯一约束 CREATE TABLE user( id INT NOT NULL, # 给name添加唯一约束 name VARCHAR(25) UNIQUE, password VARCHAR(16) ) # 给name和password两列绑定组合唯一约束 CREATE TABLE user( id INT NOT NULL, name VARCHAR(25), password VARCHAR(16), # 使用表级约束语法,name和password列组合设置唯一约束 CONSTRAINT uk_name_pwd UNIQUE(name,password) )
上面案例表示用户名和密码组合不能重复
2.2.添加唯一约束
我们除了在创建表的时候添加唯一性约束之外,也可以在创建表完成后,通过alter添加唯一约束:
# 添加唯一约束 ALTER TABLE user ADD UNIQUE(name,password) # 添加唯一约束,指定约束名称 ALTER TABLE user ADD CONSTRAINT uk_name_pwd UNIQUE(name,password) # 给单列添加唯一约束 ALTER TABLE user MODIFY name VARCHAR(20) UNIQUE;
2.3.删除约束
ALTER TABLE user DROP INDEX uk_name_pwd
三、PRIMARY KEY 约束
3.1.PRIMARY KEY 约束说明
- 主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值
- 如果是多列组合的主键约束,那么这些列都不允 许为空值,并且组合的值不允许重复。
- 每个表最多只允许一个主键,建立主键约束可以 在列级别创建,也可以在表级别上创建。
- MySQL的主键名总是PRIMARY,当创建主键约束 时,系统默认会在所在的列和列组合上建立对应的 唯一索引。
3.2.添加PRIMARY KEY 约束
- 列级模式
CREATE TABLE emp1( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20) )
- 表级模式
CREATE TABLE emp2( id INT AUTO_INCREMENT, name VARCHAR(20), CONSTRAINT emp2_id_pk PRIMARY KEY(id) )
- 组合模式
CREATE TABLE emp3( id INT NOT NULL, name VARCHAR(20), pwd VARCHAR(20), CONSTRAINT emp3_id_pk PRIMARY KEY(name,pwd) )
3.3.主键相关操作
删除主键约束
ALTER TABLE emp3 DROP PRIMARY KEY
添加主键约束
ALTER TABLE emp3 ADD PRIMARY KEY(id,name)
修改主键约束
ALTER TABLE emp3 MODIFY id INT PRIMARY KEY;
四、FOREIGN KEY 约束
4.1.FOREIGN KEY 约束
- 外键约束是保证一个或两个表之间的参照完整性, 外键是构建于一个表的两个字段或是两个表的两个字 段之间的参照关系。
- 从表的外键值必须在主表中能找到或者为空。当主 表的记录被从表参照时,主表的记录将不允许删除, 如果要删除数据,需要先删除从表中依赖该记录的数 据,然后才可以删除主表的数据。
- 还有一种就是级联删除子表数据。
注意:
- 外键约束的参照列,在主表中引用的只能是 主键或唯一键约束的列
- 同一个表可以有多个外键约束
4.2.添加FOREIGN KEY 约束
创建外键约束:
主表:
CREATE TABLE dept( dept_id INT AUTO_INCREMENT PRIMARY KEY, dept_name VARCHAR(20) );
从表
CREATE TABLE emp( emp_id INT AUTO_INCREMENT PRIMARY KEY, last_name VARCHAR(15), dept_id INT, CONSTRAINT emp_dept_id_fk FOREIGN KEY(dept_id) REFERENCES dept(dept_id) );
4.3.创建多列外键组合
创建多列外键组合,必须使用表级约束
主表:
CREATE TABLE classes( id INT, name VARCHAR(20), number INT, # 创建主键 PRIMARY KEY(name,number) );
从表:
CREATE TABLE student( id INT AUTO_INCREMENT PRIMARY KEY, class_name VARCHAR(20), class_number INT, FOREIGN KEY(class_name,class_number) REFERENCES classes(name,number) )
4.4.删除和添加外键约束
- 删除外键约束:
ALTER TABLE emp DROP FOREIGN KEY emp_dept_id_fk;
- 增加外键约束
ALTER TABLE emp ADD CONSTRAINT emp_dept_id_fk FOREIGN KEY(dept_id) REFERENCES dept(dept_id);
说明:
- FOREIGN KEY: 在表级指定子表中的列
- REFERENCES: 标示在父表中的列
- ON DELETE CASCADE(级联删除): 当父表中的列被删除 时,子表中相对应的列也被删除
- ON DELETE SET NULL(级联置空): 子表中相应的列置空
CREATE TABLE student( id INT AUTO_INCREMENT PRIMARY KEY, class_name VARCHAR(20), class_number INT, # 表级别联合外键 FOREIGN KEY(class_name,class_number) REFERENCES classes(name,number) ON DELETE CASCADE )
五、CHECK约束
MySQL可以使用check约束,但check约束对数据 验证没有任何作用,添加数据时,没有任何错误或 警告
CREATE TABLE emp4( id INT AUTO_INCREMENT, name VARCHAR(20), age INT CHECK(age>20), PRIMARY KEY(id) ); INSERT INTO emp4 VALUES(1,'top',14) INSERT INTO emp4 VALUES(2,'tom',15) INSERT INTO emp4 VALUES(3,'augus',23)
六、DEFAULT默认值约束
在插入数据时,如果不写入就使用默认值,如果写入就使用新的值
# 创建表 DROP TABLE IF EXISTS dept2 CREATE TABLE dept2( id INT(11) PRIMARY KEY AUTO_INCREMENT, name VARCHAR(25), location VARCHAR(50) DEFAULT 'shanghai'); INSERT INTO dept2 VALUES (1,'产品部','beijing') # location字段不插入则会使用默认值 INSERT INTO dept2 (id,name) VALUES (2,'项目部') INSERT INTO dept2 (name,location) VALUES ('生产部','深圳') SELECT * FROM dept2 DESC dept2
七、MySQL三大范式
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。而通常我们用的最多的就是第一范式(1NF)、第二范式(2NF)、第三范式(3NF),也就是本文要讲的“三大范式”。
7.1.第一范式(1NF)
第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。举例说明:
在上面的表中,“家庭信息”和“学校信息”列均不满足原子性的要求,故不满足第一范式,调整如下:

可见,调整后的每一列都是不可再分的,因此满足第一范式(1NF)
7.2.第二范式(2NF)
- 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)
- 第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。
举例说明:

在上图所示的情况中,同一个订单中可能包含不同的产品,因此主键必须是“订单号”和“产品号”联合组成,
但可以发现,产品数量、产品折扣、产品价格与“订单号”和“产品号”都相关,但是订单金额和订单时间仅与“订单号”相关,与“产品号”无关,这样就不满足第二范式的要求,调整如下,需分成两个表:

7.3.第三范式(3NF)
- 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
- 第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
举例说明:

上表中,所有属性都完全依赖于学号,所以满足第二范式,但是“班主任性别”和“班主任年龄”直接依赖的是“班主任姓名”,而不是主键“学号”,所以需做如下调整:

这样以来,就满足了第三范式的要求。
注意:如果把上表中的班主任姓名改成班主任教工号可能更确切,更符合实际情况,不过只要能理解就行。

浙公网安备 33010602011771号