关系数据库设计(规范化多对多映射)

时间:2010-11-19 20:22:56

标签: sql normalization relational-database database-normalization

以下是我所面临的设计问题的类似(和简化)示例:

假设您有学生,班级和成绩。学生可以参加许多不同的课程。每个班级都有很多不同的学生。每个(学生,班级)对都有一个等级。

我应该布局数据库(mysql数据库),如:

选项1)

students table - (student_id, student_name)
classes table - (class_id, class_name)
students_classes table - (student_class_id, student_id, class_id)
grades table - (student_class_id, grade)

选项2)

students table - (student_id, student_name)
classes table - (class_id, class_name)
grades table - (student_id, class_id, grade)

或者它应该被设计为其他东西?选项2现在看起来更简单了,但是在将来,我可能需要与每个(student_id,class_id)对相关的其他统计数据(在这种情况下,选项1看起来好一点吗?选项1仍然感觉有点过于复杂)。

你推荐什么?感谢。

5 个答案:

答案 0 :(得分:3)

我会亲自前往选项2。成绩的复合主键没有任何问题,它可以捕获数据模型中所需的信息。

在选项1中,除了拥有代理键​​外,students_classes没有任何意义。

在看到其他答案后编辑:

  • 2NF:成绩(非关键)仅取决于学生/班级(关键)
  • 3NF:不适用。非密钥依赖项上没有非密钥
  • BCNF:不适用,只有一个候选键

答案 1 :(得分:3)

选项3)

students table - (student_id, student_name)
classes table - (class_id, class_name)
students_classes table - (student_class_id, student_id, class_id, grade)

成绩是学生班级的一个属性。

除非等级有可能成为一个完整的实体。在这种情况下:

选项4)

students table - (student_id, student_name)
classes table - (class_id, class_name)
students_classes table - (student_class_id, student_id, class_id)
grades table - (grade_id, grade, student_class_id)

答案 2 :(得分:1)

选项2是正确的,除了它应该被称为 student_class ,反映其n :: n函数或注册为实体。而(student_id, class_id)就是PK。

成绩(如您所示)是对该复合键的1 :: 1依赖关系(不在一个或另一个元素上),而在其他任何内容上都没有,因此它是student_class的属性。< / p>

因此student_class在3NF。

如果人们没有开始盲目地将Id iot列放在移动的所有内容上,就像使用选项1一样,他们将能够更好地理解数据,从而更好地规范化。那个(选项1中的Id iot列作为起点)干扰了你(student_id, class_id)是标识符的直觉;没有额外的Id iot列及其附加索引是必要的。然后当你开始评估grade时,它对PK的依赖是显而易见的。

Id iot列会破坏数据库的Relational功能。如果您在层次结构中说了三个表,并且需要从顶部和底部表中获取一些列,则必须通过中间表。如果您有关系标识符,而不是Idiot列,则必须从底部表到顶部表,而不必阅读中间表。

在“规范化”数据库中有如此多的连接只是一半。完全的事实是,由于数据库没有正确规范化,是的,你被迫加入了比必要的更多的连接。在具有相同表的真正规范化数据库中,代码需要更少的连接。

以下是最近作业的简化版>Data Model for a College<

>IDEF1X Notation<适用于那些需要解释符号的人。

  • 请注意,只需要一个代理键。

    • 这是因为在替代方案中,(LastName + FirstName + Initials_BirthDate + BithDate)将是Person PK,并且将在5个子/孙子表中作为FK携带,这是81个字节,这是不明智的。
  • 看看你是否能够理解标识符(实线)是传给子孙的;他们有,并传达意义

  • 当我们有一个非常好的PersonId(外键并且已经是唯一的)时,为TeacherId,StudentId,StaffId添加代理键是愚蠢的。 (这些列的名称用于标识其角色。)

  • 所有业务规则均以DDL实现:FK约束;检查约束;规则。

    • 房间有一个4列的复合键;提供3列复合键;两者一起消除了双重预订。

    • 提供PK和学生PK一起构成了入学PK(与本课题相同; PK由不同的专栏组成,全部都是这样)。

答案 3 :(得分:0)

我是第三范式的粉丝,你有单独的学生,班级和成绩表,并将它们与多对多表格(如ClassStudent和GradeClass)联系起来。

<击>

但这取决于您将来如何维护它。归根结底,它归结为未来的扩展和可维护性。这就是为什么我更喜欢3NF。

修改

Axn的answer比我的要好得多。

答案 4 :(得分:-1)

这一切都取决于,真的。选项1可能是执行此应用程序的最强大方法;选项2可能会让您更快地完成此迭代。将来自选项2的变更 - > 1将来是痛苦的吗?你有多确定需要额外的灵活性?

我建议只选择选项1.查询不会那么复杂,如果你使用的是ORM(比如ActiveRecord for Rails,很多),那么差异实际上是空的。