SQL:数据库规范化,同时保留约束

标签 sql sql-server-2008 database-design polymorphism entity-attribute-value

假设我有下表:

     ____________________             ____________________
    |     Organisms      |           |       Species      |
    |--------------------|           |--------------------|
    |OrganismId (int, PK)|           |SpeciesId (int, PK) |
    |SpeciesId (int, FK) |∞---------1|Name (varchar)      |
    |Name (varchar)      |           |____________________|
    |____________________|                      1
              1                                 |
              |                                 |
              |                                 |
              ∞                                 ∞
    ______________________        ____________________          _______________
   | OrganismPropsValues  |      |   SpeciesProps     |        |     Props     |
   |----------------------|      |--------------------|        |---------------|
   |OrganismId (int, FK)  |      |PropId (int,PK,FK)  | ∞-----1|PropId (int,PK)|
   |PropId (int, FK)      |      |SpeciesId(int,PK,FK)|        |Name (varchar) |
   |Value (varchar)       |      |____________________|        |_______________|
   |______________________|                                             1
              ∞                                                         |
              |                                                         |
              -----------------------------------------------------------

对我想在这里表示的内容进行快速解释:假设我们有一个物种列表,例如猫、狗、人类等。我们还有一组属性(缩写为 Props,这样我可以更轻松地适应它)图中)适用于某些但不一定是所有物种 - 例如,这可能是尾部长度(对于有尾部的物种)、眼睛颜色(对于有眼睛的物种)等。

SpeciesProps 是一个链接器表,它定义了哪些属性适用于哪些物种 - 所以这里我们有 {Human, Eye Color}、{Dog, Eye Color}、{Cat, Eye Color}、{Dog, Tail Length} ,{猫,尾长}。我们没有 {Human, Tail Length},因为 Tail Length 显然不是适用于人类的有效属性。

有机体表保存了物种的实际“实现”——所以这里我们可能有{人类,鲍勃},{狗,鲁弗斯}和{猫,菲利克斯}。

现在我的问题是:在 OrganismPropsValues 表中,我想存储每个生物体的属性“值” - 例如,对于 Bob,我想存储 {Bob,眼睛颜色,蓝色}。对于 Rufus,我想存储 {Rufus,Eye Color,Brown} 和 {Rufus,Tail Length,20}(与 Felix 类似)。然而,我的问题是,在我详细介绍的模式中,完全可以存储 {Bob, Tail Length, 10},即使 SpeciesProps 中不存在 {Human, Tail Length} 元组。如何修改此架构,以便可以强制执行 OrganismPropsValues 中 SpeciesProps 中定义的约束,同时保持足够的标准化?

最佳答案

您正在实现 Entity-Attribute-Value反模式。这不可能是规范化的数据库设计,因为它不是关系型的。

我建议改为 Class Table Inheritance设计模式:

  • 为生物体创建一张表,其中包含所有物种共有的属性。

  • 为每个物种创建一个表,其中包含特定于该物种的属性。这些表中的每一个都与有机体具有一对一的关系,但每个属性都属于自己的列。

       ____________________             ____________________
      |     Organisms      |           |       Species      |
      |--------------------|           |--------------------|
      |OrganismId (int, PK)|           |SpeciesId (int, PK) |
      |SpeciesId (int, FK) |∞---------1|Name (varchar)      |
      |Name (varchar)      |           |____________________|
      |____________________|
                1
                |
                |
                1
       ______________________ 
      |    HumanOrganism     |
      |----------------------|
      |OrganismId (int, FK)  |
      |Sex      (enum)       |
      |Race     (int, FK)    |
      |EyeColor (int, FK)    |
      |....                  |
      |______________________|
    

这确实意味着您将创建许多表,但请将此视为以正确的关系方式存储属性的许多实际好处的权衡:

  • 您可以适本地使用 SQL 数据类型,而不是将所有内容都视为自由格式的 varchar。
  • 您可以使用约束或查找表通过一组预定义值来限制某些属性。
  • 您可以将属性设置为强制属性(即 NOT NULL)或使用其他约束。
  • 数据和索引的存储效率更高。
  • 查询对于您来说更容易编写,对于 RDBMS 来说也更容易执行。

有关此设计的更多信息,请参阅 Martin Fowler 的书 Patterns of Enterprise Application Architecture ,或我的演示Practical Object-Oriented Models in SQL ,或者我的书,SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming .

关于SQL:数据库规范化,同时保留约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7183039/

相关文章:

mysql - SQL 查询仅从另一个表中选择具有一组独占相关实体的结果

php - 如何从等于多个值的字段中提取 mysql 结果

sql - 如何调用 pl/sql 存储过程(函数,返回数值)?

sql-server - 获取第一个表上的行而不是左连接的结果集

sql-server - 无法远程连接到 SQL Server 命名实例

c# - 使用 Fluent API 添加唯一标识符

sql - Oracle 唯一约束 - 混合大小写

sql - 您如何知道 SQL 数据库何时需要更多规范化?

php - 不使用 exec() 运行 MySQL 查询列表

nhibernate - SQL 2008 对 NHibernate 的方言支持