2

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

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

我应该像这样布局数据库(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 仍然感觉有点过于复杂)。

你有什么建议吗?谢谢。

4

5 回答 5

3

Option 3)

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

Grade being an attribute of student-class.

Unless Grade has the possibility of becoming a full-fledged entity. In which case:

Option 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)
于 2010-11-19T20:41:20.637 回答
3

我个人会选择选项2。成绩的复合主键没有任何问题,它可以捕获您在数据模型中需要的信息。

在选项 1 中,students_classes 除了拥有代理键​​之外没有其他用途。

编辑,看到其他答案后:

  • 2NF:成绩(非关键)仅取决于学生/班级(关键)
  • 3NF:不适用。您在非关键依赖项上没有非关键
  • BCNF:不适用,你只有一个候选键
于 2010-11-19T20:30:56.147 回答
1

选项 2 是正确的,除了它应该被调用student_class,反映它的 n::n 函数,或者作为一个实体注册。而且(student_id, class_id)是PK。

等级(如您所展示的)是对该复合键(而不是一个或另一个元素)的 1::1 依赖,并且不依赖于其他任何内容,因此它是student_class.

因此student_class在 3NF 中。

如果人们没有Id像选项 1 那样盲目地在所有移动的东西上粘贴列,他们将能够更好地理解数据,从而更好地规范化。那(Id选项 1 中的列作为起点)干扰了您认为(student_id, class_id)是标识符的直觉;不需要Id带有附加索引的附加列。然后,当您开始评估时grade,它对该 PK 的依赖是显而易见的。

Id列会破坏数据库的关系能力。如果您说层次结构中有三个表,并且您需要从顶部和底部的表中获取一些列,那么您将被迫通过中间表。如果您有关系标识符,而不是 Idiot 列,那么您可以从底部表到顶部表,而必须读取中间表。

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

这是最近分配的简化版本中的>大学数据模型<

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

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

  • 这是因为在替代方案中,(LastName+FirstName+Initials_BirthDate+BithDate) 将是 Person PK,并且将作为 FK 在 5 个子/孙子表中携带,即 81 个字节,这是不明智的。
    .

  • 看看你是否能理解标识符(实线)被传递给子孙;它们具有并传达意义

  • 当我们有一个非常好的 PersonId(外键并且已经是唯一的)时,为 TeacherId、StudentId、StaffId 添加代理键是愚蠢的。(这些列被这样命名以识别它们的角色。)

  • 所有业务规则都在 DDL 中实现:FK 约束;检查约束;规则。

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

  • 课程 PK 和学生 PK 一起构成了注册 PK(与此问题相同;PK 由不同的列组成,仅此而已)。

于 2010-11-28T05:23:41.433 回答
0

我是第三范式的粉丝,其中你有单独的学生、班级和成绩表,并将它们与像 ClassStudent 和 GradeClass 这样的多对多表链接起来。

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

编辑

Axn 的回答比我的要好得多。

于 2010-11-19T20:27:11.310 回答
-1

这一切都取决于,真的。选项 1 可能是执行此应用程序的最稳健的方式;选项 2 可能会让您在本次迭代中更快地到达那里。选项 2 -> 1 的变化将来会那么痛苦吗?你有多确定你需要这种额外的灵活性?

我建议只选择选项 1。查询不会那么复杂,如果您使用的是 ORM(例如用于 Rails 的 ActiveRecord 等),那么差异实际上是空的。

于 2010-11-19T20:27:47.690 回答