数据库设计模式,其中一个属性仅适用于另一个属性具有特定值的情况

时间:2012-06-13 17:05:56

标签: sql design-patterns database-design naming

我经常看到这种设计模式,但没有它的名称。我很想知道设计师称这种模式以及他们如何通过合理的 DB设计来实现它。

举个简单的例子,假设学生的成绩 (1-8)。如果学生的成绩为7或8,那么他们可能是荣誉学生。那么你如何跟踪学生的这个标志,知道它只适用于某些年级的学生?

2 个答案:

答案 0 :(得分:5)

我称之为数据依赖。并非所有数据依赖关系都可以通过关系分解直接或方便地建模。使用检查约束可以很容易地处理这个:

CREATE TABLE Students (
  id SERIAL PRIMARY KEY, -- for example, something else in reality
  grade INTEGER NOT NULL,
  honors BOOLEAN,
  CONSTRAINT ensure_honors_grade 
    CHECK((honors IS NULL AND grade < 7) OR 
          (honors IS NOT NULL AND grade >= 7))
);

另一种解决方案可能是使用两个表:

CREATE TABLE Students (
  id SERIAL PRIMARY KEY,
  grade INTEGER NOT NULL,
  CONSTRAINT id_grade_unique UNIQUE (id, grade) -- needed for FK constraint below
);

CREATE TABLE Honors (
  student_id INTEGER NOT NULL,
  grade INTEGER NOT NULL,
  honors BOOLEAN NOT NULL,
  CONSTRAINT student_fk FOREIGN KEY (student_id, grade) REFERENCES Students(id, grade),
  CONSTRAINT valid_grade CHECK(grade >= 7)
);

这种替代设计更明确地说明了成绩与是否有荣誉标志之间的关系,并为7-8年级学生的进一步差异留下了空间(尽管表名应该改进)。如果你只有一个属性,荣誉布尔值,那么这可能是矫枉过正。正如@BrankoDimitrijevic所提到的,这并不强制Honors中存在一行只是因为等级为7或8,而且你还要支付一个你不需要的索引。所以有权衡;这些肯定不是唯一两种可能的设计; Branko还建议使用触发器。

对于OO设计,@ Ryan是正确的,但对于正确的关系数据库设计,通常不会通过尝试识别继承模式来解决问题。这就是面向对象的观点。关注您的访问模式以及您的代码将如何获取数据始终是非常重要的,但在关系数据库设计中,首先要求数据库中的规范化和灵活性,以及​​第二个代码,因为总是会有多个代码库获取数据,并且您希望确保数据始终有效,无论访问代码有多么多。

答案 1 :(得分:0)

您需要考虑类模型及其使用方式。您是否将Honors视为Student的布尔标志?例如if (grade > 6) Student.honor = true

通常,您可以将此视为继承映射的一种情况。请将其视为Student是父类,您的子类是HonorStudent。有多种方法可以在关系数据库中映射继承。

您可以将所有内容映射到单个表,因为基类中的所有属性都会存在,但是其中一些属性将设置为NULL或空。例如,如果HonorStudent具有属性X,则在将Student映射到表时将属性X设置为NULL。

另一种情况是每个具体类都有一个表。所以你会为Student和HonorStudent设一个单独的表。

您还可以为Student和HonorStudent提供一个具有自己属性的表格。子类只有一个表具有他们拥有(或添加)的属性,如在属性OTHER中而不是继承的属性。继承的属性将映射到父表并链接到唯一的ID。

不确定这是否是您正在寻找的答案,但这就是我的看法。