进阶 #database#er-model#design

实体关系模型(ER)

实体关系模型(Entity-Relationship Model)是用图形化的方式描述现实世界的数据结构——实体是"东西",关系是"联系",是数据库设计的第一步

🤔 如果让你设计一个选课系统——你从哪里开始?

假设学校让你设计一个新的选课系统数据库。你坐在电脑前,打开 MySQL,正准备写 CREATE TABLE 时——突然发现一个问题:

你应该建几张表?每张表里有什么列?表之间怎么关联?

如果直接开始写 SQL,大概率会出现这些状况:

  • 写了一半发现漏了一个字段,要回头改表结构
  • 设计完发现数据冗余严重,同样的信息要存好多遍
  • 上线后发现想查的数据拆不到

这就像盖楼之前没有设计图纸——直接砌砖的结果往往是返工。

🏗️ 类比:盖楼先画设计图

你不会让施工队直接开始砌砖——你得先有设计图:哪里是承重墙、哪里是走廊、房间怎么分布。

ER 图(Entity-Relationship Diagram)就是数据库的”建筑设计图”。 在写一行 SQL 之前,先用 ER 图把”有哪些数据、它们之间有什么关系”画清楚。


🎨 ER 模型的核心三要素

ER 模型只有三个基本概念,但却能描述几乎任何一种现实世界的数据场景:

① 实体(Entity)——“东西”

实体是现实世界中可以独立存在的事物,用矩形表示。

在选课系统中,实体有:

  • 学生——每个学生是一个独立个体
  • 课程——每门课是一门独立的课程
  • 教师——每位老师是一个独立个体
  • 教室——每个教室是一个物理空间

判断一个东西是不是”实体”,有个简单的标准:你能不能数出它的具体个数? 能 → 是实体。“学生”不是(泛指概念),但”张三这个学生”是。

② 属性(Attribute)——“特征”

属性是实体拥有的特征,用椭圆表示。

“学生”这个实体的属性:学号、姓名、性别、出生日期、班级……

其中能唯一标识一个实体的属性叫作主键(Primary Key),在 ER 图中用下划线标出。

            姓名

   学号───(学生)─── 班级
(主键)        │
             出生日期

③ 关系(Relationship)——“联系”

关系描述实体之间的联系,用菱形表示。

学生和课程之间存在”选课”关系——学生选课程,课程被学生选。

(学生)───── 选课 ─────(课程)

🔗 三种关系类型

实体间的联系分为三种,这是 ER 建模中最关键的概念:

1️⃣ 一对一(1:1)

一个实体最多对应另一个实体中的一个,反过来也一样。

人 ──── 身份证
  • 一个人最多有一个身份证号码
  • 一个身份证号码最多对应一个人

这在数据库设计中比较少见。学生和学号算吗?算——但学号通常是学生的”属性”而不是独立实体。

2️⃣ 一对多(1:N)

一个实体可以对应另一个实体中的多个。

班级 ──── 学生
  • 一个班级有多个学生
  • 但一个学生只属于一个班级

这是最常见的类型之一。再比如:

作者 ──── 文章      (一个作者写多篇文章)
课程 ──── 上课记录   (一门课程有多次课)

3️⃣ 多对多(M:N)

一个实体可以对应另一个实体中的多个,反过来也一样。

学生 ──── 课程    (通过"选课")
  • 一个学生可以选择多门课程
  • 一门课程可以被多个学生选择

这是另一个常见类型。注意:多对多关系在数据库中无法直接实现——你需要拆成两个”一对多”。具体怎么拆?直接说答案:引入一个中间表(选课记录表),后面关系模型部分会详细解释。

🚌 类比:公交车线路和站点

一对一 = 你的座位号(一个座位对应一个人,一个人对应一个座位)

一对多 = 一条公交线路有多个站点(一条线路→多个站点)

多对多 = 公交线路和站点的关系——一条线路经过多个站点,一个站点有多条线路经过


📋 完整例子:设计选课系统的 ER 模型

让我们一步步画出选课系统的 ER 图:

第 1 步:找出实体

选课系统中明显有:

  • 学生(Student)
  • 课程(Course)
  • 教师(Teacher)

第 2 步:找出关系

  • 学生和课程:选课(M:N——一个学生选多门课,一门课被多个学生选)
  • 教师和课程:授课(1:N——一个教师教多门课,但一门课通常只有一个主讲教师)

第 3 步:找出每个实体的属性

  • 学生:学号(主键)、姓名、班级、入学年份
  • 课程:课程号(主键)、课程名、学分、学时
  • 教师:工号(主键)、姓名、职称、所属院系

第 4 步:画出完整的 ER 图

            姓名             班级
              │               │
   学号────(学生)──── 入学年份

              │ M

            (选课)
              │ N

   课程号───(课程)          工号───(教师)
      │        │                │       │
   课程名     学分            姓名    职称

             学时

              │ N            ↑
            (授课)──────────│ 1

注意”选课”关系还有一个自己的属性:成绩—— 成绩既不属于学生(不是学生本身的特征),也不属于课程(不是课程本身的特征),而是”选课”这个关系的属性。这在 ER 建模中很常见。

(学生)───── 选课(成绩)──────(课程)

🧠 为什么不能跳过 ER 建模直接写 SQL?

很多初学者觉得画 ER 图很麻烦——“反正最终都要写成表,为什么不直接建表?”

原因很简单:

坏例子:直接建表

CREATE TABLE 选课 (
    学号 INT,
    学生姓名 VARCHAR(50),
    学生班级 VARCHAR(20),
    课程号 INT,
    课程名 VARCHAR(100),
    学分 INT,
    教师姓名 VARCHAR(50),
    成绩 INT
);

这张表把所有数据塞进了一张表——三秒建好,但问题一堆:

  • 冗余:同一个学生的姓名在每门选课记录里重复存
  • 更新异常:学生转班了,要改所有相关行的班级字段
  • 插入异常:新开了一门课但还没人选——课程信息存不进去(因为没有学生)
  • 删除异常:删除某个退课学生的记录,可能把课程信息也删没了

好例子:先画 ER 图再建表

通过 ER 建模,你会自然而然地拆成多张表:

  • 学生表(学号、姓名、班级)
  • 课程表(课程号、课程名、学分)
  • 选课记录表(学号→外键、课程号→外键、成绩)
  • 教师表(工号、姓名、职称)

这样每个数据只存一份,不存在冗余和异常问题。


📝 小结

概念一句话
实体(Entity)现实世界中的”事物”,用矩形表示
属性(Attribute)实体的”特征”,用椭圆表示
关系(Relationship)实体间的”联系”,用菱形表示
1:1一对一(一个身份证对应一个人)
1:N一对多(一个班级有多个学生)
M:N多对多(学生选课),需拆成两个 1:N

🎯 核心原则:先画清楚再写代码。 ER 图是数据库的设计蓝图——它让你在设计阶段而不是实现阶段发现问题。

为什么先学这个? ER 模型是数据的”概念设计”,但计算机不能直接理解 ER 图。下一步是把 ER 图转化为数学化、可计算的模型——关系模型与关系代数