1.1概念须知
1. 主键(Primary Key)
定义
主键是表中一个或多个字段的组合,用于唯一标识表中的每一行记录。主键字段的值必须是唯一的,且不能为NULL
。一般情况下是一个字段即可,在单个字段无法表示其唯一性是会用复合主键,比如多对多关系关联表中的外键
特点
- 唯一性:主键字段的值必须是唯一的,不能有重复值。例如,在学生表中,学生编号(
student_id
)可以作为主键,因为每个学生的编号是唯一的。 - 非空性:主键字段的值不能为
NULL
。在插入或更新记录时,必须为每个主键字段提供一个值。 - 不可变性:主键值一旦确定,通常不应更改,因为主键值的更改可能会影响与其他表的关联关系。
示例
假设有一个学生表(Students
),其结构如下:
CREATE TABLE Students (
student_id INT PRIMARY KEY, -- 主键字段
student_name VARCHAR(50),
age INT,
class_id INT
);
在这个表中,student_id
被定义为主键,用于唯一标识每个学生。
2. 外键(Foreign Key)
定义
外键是表中的一个字段或字段组合,用于引用另一个表的主键,从而建立两个表之间的关系。外键的作用是确保数据的引用完整性,即外键字段的值必须是被引用表中主键的有效值,或者为NULL
。
特点
- 引用完整性:外键字段的值必须是被引用表中主键的有效值,或者为
NULL
。例如,如果学生表中的class_id
是外键,引用班级表(Classes
)的class_id
,那么class_id
的值必须在班级表中存在。 - 依赖性:外键字段的值依赖于被引用表的主键值。如果被引用表中的主键值被删除或更改,外键字段的值也会受到影响。
- 级联操作:在某些情况下,可以设置外键的级联操作,如级联删除(
ON DELETE CASCADE
)或级联更新(ON UPDATE CASCADE
)。例如,如果删除了一个班级,可以设置级联删除,自动删除所有引用该班级的学生记录。
示例
假设有一个班级表(Classes
)和学生表(Students
),其结构如下:
CREATE TABLE Classes (
class_id INT PRIMARY KEY, -- 班级表的主键
class_name VARCHAR(50)
);
CREATE TABLE Students (
student_id INT PRIMARY KEY, -- 学生表的主键
student_name VARCHAR(50),
age INT,
class_id INT,
FOREIGN KEY (class_id) REFERENCES Classes(class_id) -- 外键字段
);
1.2数据实体间的关系
- 一对一关系
- 这种关系比较少见。例如,一个学校只有一个校长,一个校长只管理一个学校。在设计表时,可以在任意一个表中添加另一个表的主键作为外键。比如学校表(school)的主键是school_id,校长表(principal)的主键是principal_id,可以在校长表中添加school_id作为外键,也可以在学校表中添加principal_id作为外键。一般选择在业务操作更频繁的表中添加外键,如果经常通过学校查找校长信息,就在校长表中添加school_id外键。
- 一对多关系
-
- 这是最常见的关系类型。例如,一个班级有多个学生,但一个学生只属于一个班级。在这种情况下,在“多”的一方的表中添加“一”的一方表的主键作为外键。班级表(class)的主键是class_id,学生表(student)的主键是student_id,那么在学生表中添加class_id作为外键。这样可以通过class_id将学生和班级关联起来,方便查询某个班级的所有学生等操作。
- 多对多关系
-
- 例如,学生和课程之间的关系。一个学生可以选修多门课程,一门课程也可以被多个学生选修。对于这种关系,需要创建一个关联表(也叫连接表或中间表)。关联表通常包含两个主表的主键作为外键。可以创建一个选修表(enrollment),在选修表中有student_id和course_id两个字段,它们分别作为学生表和课程表的外键。同时,这个关联表还可以添加其他属性,如成绩(score)等信息。
1.3设计数据库的表
1. 确定主键
非关联表主键设计:
把握主键特性,唯一,非Null,不可改变等特性即可,类比身份证号。
关联表主键设计:
-
- 一种是将两个外键组合成复合主键
- 新建一个单独的主键
2. 确定外键
-
- 外键的数据类型和长度要与被引用的主键完全一致
- 要设置外键约束,以保证数据的完整性,例如外键引用其他表的主键
- 当被引用的主键记录被删除时,可以设置级联删除(关联表中对应的记录也会被删除)或者设置为禁止删除(除非先删除关联表中的记录)等操作
3. 确定其他字段
- 自己表本身需要的字段,比如学生的姓名班级课程等等
- 关联表中的其他字段也可以引用进来
4. 考虑数据库的完整性约束
- 实体完整性
-
- 确保每个表都有主键,主键值必须唯一且非空。在设计关联表时,无论是作为主表还是关联表,都要遵循这个原则。例如,在学生表中,student_id作为主键,数据库系统会自动保证每个学生的student_id是唯一的,且在插入数据时不能插入空值。
- 参照完整性
-
- 这是通过外键约束来实现的。在外键字段中,只能插入被引用表中存在的主键值,或者插入空值(如果外键字段允许为空)。例如,在选修表中插入数据时,student_id和course_id必须是学生表和课程表中存在的主键值,否则插入操作会失败。这样可以保证关联表中的数据与被关联表中的数据保持一致,避免出现孤立的记录。
- 用户定义的完整性
-
- 根据业务规则添加约束。例如,在选修表中,成绩字段score的值应该在0 - 100之间,可以在数据库表结构中设置检查约束(CHECK约束),如
CHECK (score >= 0 AND score <= 100)
,以确保数据符合业务逻辑。
- 根据业务规则添加约束。例如,在选修表中,成绩字段score的值应该在0 - 100之间,可以在数据库表结构中设置检查约束(CHECK约束),如
5. 优化关联表设计
- 索引优化
-
- 在关联表的外键字段上创建索引。因为关联查询经常会在外键字段上进行连接操作,索引可以加快连接速度。例如,在选修表的student_id和course_id上创建索引,当执行类似
SELECT * FROM students JOIN enrollment ON students.student_id = enrollment.student_id;
这样的查询时,数据库可以利用索引快速找到匹配的记录。 - 对于多对多关系的关联表,如果查询经常基于某个属性字段(如成绩),也可以在这个字段上创建索引。但是要注意,索引会占用额外的存储空间,并且在插入、更新和删除数据时会增加维护索引的开销,所以要合理创建索引。
- 在关联表的外键字段上创建索引。因为关联查询经常会在外键字段上进行连接操作,索引可以加快连接速度。例如,在选修表的student_id和course_id上创建索引,当执行类似
- 表结构简化
-
- 避免在关联表中添加过多冗余字段。例如,在选修表中,不需要添加学生的姓名和课程的名称等冗余信息,这些信息可以通过关联学生表和课程表来获取。过多的冗余字段会增加存储空间的浪费,并且在数据更新时需要同步更新多个地方,容易出现数据不一致的情况。
6. 示例
我们有三个表:
- 学生表(
Students
):存储学生的基本信息。 - 课程表(
Courses
):存储课程的基本信息。 - 选修表(
Enrollments
):存储学生选修课程的记录,使用复合主键来确保唯一性。
--学生表
CREATE TABLE Students (
student_id INT,
student_name VARCHAR(50),
age INT,
PRIMARY KEY (student_id) -- 主键
);
--课程表
CREATE TABLE Courses (
course_id INT,
course_name VARCHAR(50),
PRIMARY KEY (course_id) -- 主键
);
--选修表
CREATE TABLE Enrollments (
student_id INT,
course_id INT,
grade CHAR(2), -- 学生在这门课程的成绩
PRIMARY KEY (student_id, course_id), -- 复合主键
FOREIGN KEY (student_id) REFERENCES Students(student_id), -- 外键引用学生表
FOREIGN KEY (course_id) REFERENCES Courses(course_id) -- 外键引用课程表
);