假设我有下表:
____________________ ____________________
| 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/