多对多不能靠在一边塞字段解决
以学生选课为例,一个学生可以选多门课,一门课也可以被多个学生选择。如果把课程编号都塞进学生表的一个字段里,就会出现重复值、查询困难、更新麻烦等问题。
关系数据库更自然的做法,是建立一张“选课表”。每一行表示一个学生和一门课程之间的一次选择关系。这样既能表达多对多,也方便记录成绩、选课时间、任课教师等联系属性。
| 表 | 典型字段 | 作用 |
|---|---|---|
| 学生表 | 学生编号、姓名、班级 | 保存学生实体属性 |
| 课程表 | 课程编号、课程名、学分 | 保存课程实体属性 |
| 选课表 | 学生编号、课程编号、成绩、选课时间 | 保存学生和课程之间的联系 |
联系表里放什么
联系表至少要包含两端实体的主键,通常作为外键引用原实体表。很多场景下,这两个外键还可以共同组成联合主键,表示同一个学生对同一门课程只能有一条选课记录。
如果联系本身有属性,也放在联系表里。比如学生选课关系里的成绩,不属于单纯的学生,也不属于单纯的课程,而是属于某个学生选某门课这件事。
两端主键学生编号、课程编号通常进入选课表
外键分别引用学生表和课程表
联系属性成绩、选课时间等放在联系表中
为什么这类题经常考学生选课、用户角色、订单商品
这些场景天然就是多对多:一个学生多门课,一门课多个学生;一个用户多个角色,一个角色多个用户;一个订单多个商品,一个商品也会出现在多个订单中。题干只要出现“两边都可以有多个”,就要警惕联系表。
老师讲题时常说一句:多对多不要硬塞到任意一端。硬塞会破坏数据规范性,也会让查询和维护变得很难。
考场判断口诀
一对多,外键放多端;多对多,单独建联系表;一对一,看约束和参与情况。这个口诀不复杂,但要能结合题干说出原因。
如果题目问“为什么不能把所有课程写在学生表一个字段中”,答案就要回到规范化和维护性:字段值不应重复堆叠,查询、插入、删除、修改都会变麻烦。
相关题目解析
下面这些题目和本专题的判断方法关联较强,适合读完概念后回到具体题干里校验理解。
- ER 图中的多对多联系转换成关系模式时怎么处理?ER 模型 / 多对多联系
- ER 图一对多联系转换成关系表时外键放在哪里?ER 图 / 关系模式转换