[MySQL] 表设计

画师:竹取工坊

大佬们好!我是Mem0rin!现在正在准备自学转码。

如果我的文章对你有帮助的话,欢迎关注我的主页Mem0rin,一起进步!


文章目录


MySQL 表设计

表设计的目标是把业务对象及其关系转换为清晰、稳定的数据库结构,同时减少数据冗余和增删改异常。

一、表设计的基本流程

(一)设计步骤

  1. 从需求中提取实体,如学生、班级和课程,每个实体通常对应一张表。
  2. 确定实体的属性,属性通常对应表中的字段。
  3. 确定实体之间的一对一、一对多或多对多关系。
  4. 根据范式检查表结构,减少重复数据和依赖问题。
  5. 使用 SQL 创建表,并设置主键、外键等约束。

(二)通用建表语法

sql 复制代码
-- 创建数据表
CREATE TABLE table_name (
    column1 data_type constraint,
    column2 data_type constraint,
    PRIMARY KEY (column1),
    FOREIGN KEY (column2) REFERENCES other_table (column2)
);

二、范式

范式用于规范表中字段之间的依赖关系;一对一、一对多和多对多用于描述实体之间的数量关系,两者不是同一概念。

常见范式包括第一范式(1NF)、第二范式(2NF)、第三范式(3NF)和 BC 范式(BCNF)。实际设计中通常先掌握前三种范式。

(一)第一范式(1NF)

1. 基本要求

第一范式要求每个字段保存一个不可再分的值,不能在一个字段中存放多个重复项或组合信息。

例如,下面的学生表符合第一范式:

学号 姓名 年龄 班级名称
10001 张三 20 101班

如果把学校名称、地址和电话全部放入一个"学校信息"字段,后续查询和修改会比较困难,应将它们拆分为独立字段。

2. 拆分示例
不推荐的字段 拆分后的字段
学校信息 学校名称、学校地址、学校电话
联系方式 手机号、电子邮箱

"不可再分"需要结合业务判断。例如完整地址在某些业务中可以作为一个字段,在需要按省市统计时则应继续拆分。

(二)第二范式(2NF)

1. 基本要求

第二范式要求:在满足第一范式的基础上,每个非主属性都必须完全依赖于候选键,不能只依赖复合候选键的一部分。

  • 候选键是能够唯一标识一条记录的最小字段集合。
  • 非主属性是不属于任何候选键的字段。
  • 部分依赖通常出现在候选键由多个字段组成的表中。

如果一张表的所有候选键都只有一个字段,它会自动满足第二范式;仅仅"没有复合主键"并不能保证一定满足第二范式,因为还可能存在其他复合候选键。

2. 反例分析

假设成绩表包含以下字段:

学号 学生姓名 年龄 课程编号 课程名称 学分 成绩

其中,学号 + 课程编号 可以共同确定一条成绩记录,但各字段的依赖关系不同:

  • 学生姓名、年龄只依赖学号。
  • 课程名称、学分只依赖课程编号。
  • 成绩依赖学号和课程编号的组合。

部分字段只依赖复合键的一部分,因此该表不满足第二范式。

3. 拆分方法
字段
学生表 学号、姓名、年龄
课程表 课程编号、课程名称、学分
成绩表 学号、课程编号、成绩

拆分后可以减少以下问题:

  • 数据冗余:学生信息和课程信息不再重复保存。
  • 更新异常:修改课程学分时只需更新课程表。
  • 插入异常:还没有成绩时也能先录入学生和课程。
  • 删除异常:删除成绩不会连带丢失学生或课程信息。

(三)第三范式(3NF)

1. 基本要求

第三范式要求:在满足第二范式的基础上,非主属性不能通过另一个非主属性间接依赖候选键,即不能存在传递依赖。

例如,学生表包含以下字段:

学号 姓名 年龄 学院编号 学院名称 学院电话 学院地址

依赖关系为:

学号 → 学院编号 → 学院名称、学院电话、学院地址

学院信息通过学院编号间接依赖学号,形成传递依赖。

2. 拆分方法
字段
学院表 学院编号、学院名称、学院电话、学院地址
学生表 学号、姓名、年龄、学院编号

学生表只保留学院编号,并通过外键关联学院表。这样修改学院信息时,不需要更新每一条学生记录。

三、实体之间的关系

(一)一对一关系

一条记录最多对应另一张表中的一条记录,例如账号与用户详细信息。

常见设计方式有两种:

  1. 信息较少且生命周期相同时,合并到一张表。
  2. 信息较多或职责不同,拆分为两张表,并在外键上添加 UNIQUE 约束。

账号系统通常可以先根据账号和密码找到用户编号,再通过用户编号查询详细信息。

(二)一对多关系

一个班级可以有多名学生,但一名学生只属于一个班级。设计时把"一"方的主键放到"多"方作为外键。

主要字段
班级表 class_idclass_name
学生表 student_idnameclass_id

(三)多对多关系

一名学生可以选择多门课程,一门课程也可以被多名学生选择。多对多关系需要增加中间表。

主要字段
学生表 student_idname
课程表 course_idcourse_name
成绩表 student_idcourse_idscore

成绩表中的两个外键连接学生表和课程表,二者也可以组成复合主键,避免同一名学生重复添加同一门课程。

四、建表示例

(一)班级表与学生表

sql 复制代码
-- 创建班级表
CREATE TABLE class (
    class_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    class_name VARCHAR(20) NOT NULL
);

-- 创建学生表,班级与学生是一对多关系
CREATE TABLE student (
    student_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    sn VARCHAR(20) NOT NULL UNIQUE,
    name VARCHAR(50) NOT NULL,
    age INT,
    mail VARCHAR(50),
    class_id BIGINT,
    FOREIGN KEY (class_id) REFERENCES class (class_id)
);

(二)课程表与成绩表

sql 复制代码
-- 创建课程表
CREATE TABLE course (
    course_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    course_name VARCHAR(50) NOT NULL,
    credit DECIMAL(3, 1) NOT NULL
);

-- 创建成绩表,连接学生表与课程表
CREATE TABLE score (
    student_id BIGINT NOT NULL,
    course_id BIGINT NOT NULL,
    score DECIMAL(5, 2),
    PRIMARY KEY (student_id, course_id),
    FOREIGN KEY (student_id) REFERENCES student (student_id),
    FOREIGN KEY (course_id) REFERENCES course (course_id)
);
相关推荐
Dxy12393102169 小时前
Python 如何使用 MySQL 的事务
python·mysql
xiaoye-duck13 小时前
MySQL 表约束全解:从基础约束到外键关联规则
数据库·mysql
冷凝娇15 小时前
【MySQL】2026总结(二)
数据库·mysql
wWYy.16 小时前
Mysql:Read View
数据库·mysql
—Miss. Z—17 小时前
存储过程、用户定义函数、触发器和游标
数据库·mysql
小码农 - 初18 小时前
MySQL 的约束
mysql
文人sec18 小时前
MySQL事务与索引做了什么?
android·笔记·mysql
Dear~yxy18 小时前
MySQL企业级实战
数据库·mysql
晚安code18 小时前
MySQL 开发规范清单:建表、索引、SQL、ORM 四块一次讲透
数据库·sql·mysql
王琦031819 小时前
第二章 MySQL集群高可用架构
mysql·adb·架构