目录
[5 数据库约束](#5 数据库约束)
[5.1 约束类型](#5.1 约束类型)
[5.2 NOT NULL 非空约束](#5.2 NOT NULL 非空约束)
[5.3 UNIQUE 唯一约束](#5.3 UNIQUE 唯一约束)
[5.4 PRIMARY KEY 主键约束](#5.4 PRIMARY KEY 主键约束)
[5.5 FOREIGN KEY 外键约束](#5.5 FOREIGN KEY 外键约束)
[5.6 DEFALUT 默认值约束](#5.6 DEFALUT 默认值约束)
[5.7 CHECK 约束](#5.7 CHECK 约束)
[6 数据库设计------表设计](#6 数据库设计——表设计)
[6.1 范式](#6.1 范式)
[6.2 第一范式](#6.2 第一范式)
[6.3 第二范式](#6.3 第二范式)
[6.4 第三范式](#6.4 第三范式)
[6.5 设计过程](#6.5 设计过程)
[6.6 E-R图](#6.6 E-R图)
[6.6.1 一对一(1:1)](#6.6.1 一对一(1:1))
[6.6.2 一对多(1:N)](#6.6.2 一对多(1:N))
[6.6.3 多对多(M:N)](#6.6.3 多对多(M:N))
5 数据库约束
数据库约束是指对数据库中的数据所施加的规则或条件,用于确保数据的准确性和可靠性。这些约束可以使基于数据类型、值范围、唯一性、非空等规则,以确保数据的正确性和相容性。
5.1 约束类型
| 类型 | 说明 |
|---|---|
| NOT NULL 非空约束 | 指定非空约束的列不能存储 NULL 值 |
| DEFAULT 默认约束 | 当没有给列赋值时使用的默认值 |
| UNIQUE 唯⼀约束 | 指定唯⼀约束的列每行数据必须有唯⼀的值 |
| PRIMARY KEY 主键约束 | NOT NULL 和 UNIQUE的结合,可以指定⼀个列或多个列,有助于防⽌数据 重复和提高数据的查询性能 |
| FOREIGN KEY 外键约束 | 外键约束是⼀种关系约束,用于定义两个表之间的关联关系,可以确保数据 的完整性和⼀致性 |
| CHECK 约束 | 用于限制列或数据在数据库表中的值,确保数据的准确性和可靠性 |

5.2 NOT NULL 非空约束
定义表示某列不允许为NULL时,可以为列添加非空约束。
- 比如创建⼀个学⽣表,学⽣名为NULL时,这条记录是不完整的

5.3 UNIQUE 唯一约束
指定了唯一约束的列,该列的值在所有记录中不能重复,比如身份证号和学号。


5.4 PRIMARY KEY 主键约束
主键约束唯⼀标识数据库表中的每条记录。
主键必须包含唯⼀的值,且不能包含 NULL 值。
每个表只能有⼀个主键,可以由单个列或多个列组成。
通常为每张表都指定⼀个主键,主键列建议使用BIGINT类型

一个主键可以包含多个列



表中不能有多个主键
sql
drop table student;
# 重构学生表
create table student(
id bigint PRIMARY KEY auto_increment,
name varchar(20) primary key
);
ERROR 1068 (42000): Multiple primary key defined # 报错
复合主键:有多个列共同组成的主键,主键冲突是否已多个列的组成进行判定
sql
# 复合主键:有多个列共同组成的主键,主键冲突是否已多个列的组成进行判定
drop table student;
# 重构学生表
create table student(
id bigint,
name varchar(20),
PRIMARY KEY (id, name)
);
# 插入数据
insert into student(id, name) values (1, '张三');
# 重复插入主键冲突,此时主键值由id和name两个列共同决定
insert into student(id, name) values (1, '张三');
# 报错:1062 - Duplicate entry '1-张三' for key 'student.PRIMARY'
# 修改id 值插入成功
insert into student(id, name) values (2, '张三');
select * from student;
5.5 FOREIGN KEY 外键约束
外键用于定义主表和从表之间的关系
外健约束定义在从表的列上,主表关联的列必须是主键或唯一约束
当定义外键后,要求从表中的外键列数据必须在主表的主键或唯一列存在或为null
- 创建班级表(主表),并初始化数据
sql
# 创建班级表(主表),并初始化数据
drop table if exists class;
# 建表
create table class (
id bigint primary key auto_increment,
name varchar(20) not null
);
# 初始化数据
insert into class (name) values ('java01'), ('java02'), ('java03'), ('C++01'),
('C++02');
select * from class;
-- --------------------------------------
# 重构学生表(从表),加入外键约束
# 语法
drop table if exists student;
# 重构表
create table student(
id bigint PRIMARY KEY auto_increment,
name varchar(20) not null,
age int DEFAULT 18,
class_id bigint,
foreign key (id) REFERENCES class(id) # 创建外键约束
);
# 查看表结构,可以Key列的值为MUL表示外键约束的列
desc student;
# 正常插入数据
# 班级编号在主表中存在
insert into student(name, class_id) values ('张三', 1), ('李四', 2);
select * from student;


5.6 DEFALUT 默认值约束
DEFALUT约束用于向列中插入默认值,如果没有为列设置值,那么会将默认值设置到该列


5.7 CHECK 约束
可以应用于⼀个或多个列,用于限制列中可接受的数据值,从而确保数据的完整性和准确性。
sql
drop table if exists student;
# 加⼊CHECK约束
create table student(
id bigint PRIMARY KEY auto_increment, # 设置⾃增主键
name varchar(20) not null,
age int DEFAULT 18,
gender char(1),
check (age >= 16),
check (gender = '男' or gender = '⼥')
);
# 正常插⼊数据
insert into student(name, age, gender) values ('张三', 17, '男'), ('李
四', 19, '⼥');
select * from student;

6 数据库设计------表设计
6.1 范式
-
数据库的范式是一组规则。在设计关系数据库时,遵从不同的规则要求,设计出合理的关系行数据库库,这些不同的规范要求称为不同的范式。
-
关系型数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德 范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式),越高的范式数据库冗余越小。然而,普遍认为范式越高虽然对数据关系有更好的约束性,但也可能导致数据库IO更繁忙,因此 在实际应用中,数据库设计通常只需满足第三范式即可。
-
数据库IO更繁忙------指原本从一个表中可以查出来的数据,这时需要从多个表中查。
6.2 第一范式
定义:
-
数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,对象等非原子数据。
-
在关系型数据库的设计中国,满足第一范式是对关系模式的基本要求。不满足第一范式的数据库不能被称为关系型数据库。
示例:

6.3 第二范式
定义:
-
在满足第一范式的基础上,不存在非关键字段(非主键字段)对任意候选键(可以理解为主键,唯一键,用来标识数据行)的部分函数依赖。存于表中定义了复合主键(主键包含多个列)的情况下。
-
候选键:可以唯一标识一行数据的列或者列的组合,可以从候选键中选一个或多个当做表的主键。
示例:
- 需求:学生可以选修课程,课程有对应的学分,学生考试后每门课程会产生相应的成绩
反例:

不满足第二范式可能出现以下问题:
- 数据冗余
-
更新异常
-
插入异常
-
删除异常
正例:

6.4 第三范式
定义:
- 在满足第二范式的基础上,不存在吧非关键字段,对任意候选键的传递依赖。
示例:
- 要求学生表中记录学生所属的学院,在满足第⼆范式的基础上对学生表做出修改------该需求实际上设计两个实体,一个是学生,一个是学院。
反例:

正例:

6.5 设计过程
-
从现实业务中抽象得到概念类
概念类是从现实世界中抽象出来的,在需求分析阶段就需要确定下来
- 类对应了数据库设计中的实体,实体对应了数据库中的表
- 类中的属性对应实体中的属性,实体的属性对应了表中的列
- 确定实体与实体之间的关系,并画出E-R画,⽅便项⽬参与⼈员理解与沟通
- 根据E-R图完成SQL语句的编号并创建数据库
6.6 E-R图
E-R图包含以下三种基本组成: 实体:指数据对象,用规矩框表示,比如用户、学生、班级等。
属性:实体的特性,用椭圆形或圆角矩形表示,入学生的姓名、年龄。
关系:实体间的联系,⽤菱形框表示,并标明关系的类型,并⽤直线将相关实体与关系连接起来。

6.6.1 一对一(1:1)



6.6.2 一对多(1:N)
-
⼀个学⽣实体包含的属性有:真实姓名,学号,年龄,性别,入学时间
-
⼀个班级实体包含的属性有:班级名,学生⼈数
-
⼀个班级中有多个学生,所以班级实体与学生实体是⼀对多的关系,反过来说学生实体与班级实体 是多对⼀着么,用E-R图表示如下:


6.6.3 多对多(M:N)
-
⼀个学⽣实体包含的属性有:真实姓名,学号,年龄,性别,入学时间
-
⼀个课程实体包含的属性有:课程名
-
⼀个学生可以选修改多门课程,一门课程也可以被多名学生选修改,所以学生与课程之间是多对多 关系,用E-R图表示如下:

- 对于多对多关系,可以使用中间表进行记录,比如⼀个学生参加了某⼀门课程的考试得到了相应的 成绩,用E-R图表示如下:


练习:
sql
# 设计表
-- ------------ 用户与账户的一对一关系 -----------
# 在用户实体中添加对账户实体的关联
drop table if exists users;
create table users(
id bigint primary key auto_increment,
name varchar(20) not null,
nickname varchar(20),
phone_num varchar(11),
email varchar(50),
genter tinyint(1),
account_id bigint
);
drop table if exists account;
create table account(
id bigint primary key auto_increment,
username varchar(20) not null,
password varchar(32) not null
);
# 在账户实体中添加对用户实体的关联
drop table if exists users;
create table users (
id bigint primary key auto_increment,
name varchar(20) not null,
nickname varchar(20),
phone_num varchar(11),
email varchar(50),
gender tinyint(1)
);
drop table if exists account;
create table account (
id bigint primary key auto_increment,
username varchar(20) not null,
password varchar(32) not null,
users_id bigint
);
-- ------------ 学生与班级的一对多关系 --------------
# 班级表
drop table if exists class;
create table class (
id bigint primary key auto_increment,
name varchar(20)
);
# 学生表
drop table if exists student;
create table student (
id bigint primary key auto_increment,
name varchar(20) not null,
sno varchar(10) not null,
age int default 18,
gender tinyint(1),
enroll_date date,
class_id bigint
);
-- ------------- 学生、课程与成绩的多对多关系 ------------------
# 学生表
drop table if exists student;
create table student (
id bigint primary key auto_increment,
name varchar(20) not null,
sno varchar(10) not null,
age int default 18,
gender tinyint(1),
enroll_date date,
class_id bigint,
foreign key (class_id) references class(id)
);
# 课程表
drop table if exists course;
create table course (
id bigint primary key auto_increment,
name varchar(20)
);
# 分数表
drop table if exists score;
create table score (
id bigint primary key auto_increment,
score float,
student_id bigint,
course_id bigint,
foreign key (student_id) references student(id),
foreign key (course_id) references course(id)
);