简介及相关资料:
以下示例说明了我面临的问题:
动物有一个种族,可以是猫或狗。Cat可以是Siamese或Persian。狗可以是德国牧羊犬或拉布拉多猎犬。
动物是一个强大的实体,而它的种族是一个属性,可以具有两个提供的值(猫或狗)之一。 这两个值都很复杂(我在这里只添加了狗/猫的类型来说明问题,但也可能有猫/狗的名字和其他一些东西)。
问题:
我不知道如何为此示例创建关系表。
我为解决问题所做的努力:
我尝试使用 Chen 的符号绘制 ER 图,这代表了问题,但作为初学者,我不知道我是否做对了。这是我得到的:
如果我画错了,我深表歉意,如果是这样,请纠正我。我不希望简单地获得“免费解决方案”,还希望学习如何处理这个问题,以便将来我可以自己解决。
我唯一想到的就是创建两个单独的表格,一张给猫,一张给狗。此外,Animal表中的种族属性只会存储cat或dog值。像这样的东西:
Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >
我真的对我的解决方案有一种不好的感觉,我担心它是错误的,因此下面的问题。
问题:
- 如何将我的示例转换为 ER 图?
- 如何将该 ER 图转换为关系表?
如果需要更多信息,请发表评论,我会尽快更新我的帖子。也可以随意添加适当的标签,因为我在这里相当新。
谢谢你。
这种情况的正确结构是子类/继承模型,几乎与我在这个答案中提出的概念相同:值的异构有序列表。
这个问题中提出的模型实际上非常接近,因为
Animal
实体包含类型(即race
)和所有类型共有的属性。但是,需要进行两个小的更改:从各自的实体中删除 Cat_ID 和 Dog_ID 字段:
这里的关键概念是一切都是
Animal
,而不管race
:Cat
、Dog
、Elephant
等等。鉴于该起点,任何特定race
的Animal
并不真正需要单独的标识符,因为:Animal_ID
是独一无二的Cat
和将来添加的Dog
任何其他race
实体本身并不完全代表任何特定的Animal
; 它们仅在与父实体中包含的信息结合使用时才有意义,Animal
.因此,, , etc 实体中的
Animal_ID
属性既是返回实体的 PK 又是 FK。Cat
Dog
Animal
区分类型
breed
:仅仅因为两个属性共享相同的名称并不一定意味着这些属性是相同的,即使名称相同意味着这种关系。在这种情况下,您真正拥有的实际上
CatBreed
是DogBreed
单独的“类型”初始注释
VARCHAR
但如果您需要存储标准 ASCII 集之外的任何内容,您应该真正使用NVARCHAR
.Race
不是CatBreed
自动DogBreed
递增的(即 T-SQL 中的 IDENTITY),因为它们是应用程序常量(即它们是应用程序的一部分),它们是数据库并enum
在 C#(或其他语言)中表示为 s。如果添加值,它们将在受控情况下添加。我保留对通过应用程序传入的用户数据使用自动增量字段。“品种”作为“种族”——具体方法
第一组表是查找/类型表:
第二个清单是主要的“动物”实体:
这第三组表是补充的子类实体,它们完成了每个表的
Race
定义Animal
:使用共享
breed
类型的模型显示在“附加说明”部分之后。补充说明
breed
似乎是混淆的焦点。jcolebrand 建议(在对问题的评论中)这breed
是一个在不同 s 之间共享的属性race
,而其他两个答案已将其集成到他们的模型中。然而,这是一个错误,因为 的值breed
不会在 的不同值之间共享race
。是的,我知道另外两个提议的模型试图通过race
将breed
. 虽然这在技术上解决了关系问题,但它无助于解决如何处理非公共属性的整体建模问题,也无助于解决race
没有breed
. 但是,如果这样的属性保证存在于所有Animal
s,我也会为此提供一个选项(如下)。Animal
),或race
s 的所有属性都存储在Animal
实体中,这是表示此数据的一种非常扁平(且几乎非关系)的方式。是的,人们一直都在这样做,但这意味着每行有许多 NULL 字段用于不用于该特定的属性,并且race
知道每行的哪些字段与race
该记录的特定相关联。race
of 。并且即使 ALL有一个,由于前面已经提到过的内容,这不会改变结构:这取决于(即for与for不同)。Animal
breed
Animal
breed
breed
breed
race
breed
Cat
breed
Dog
“品种”作为公共/共享财产方法
请注意:
下面的 SQL 可以在与上述模型相同的数据库中运行:
Race
是一样的Breed
桌子是新的Animal
表都附加了一个2
Breed
是现在的共同财产,在主/父实体中没有注明似乎也不正确Race
(即使它在技术上是正确的)。所以,RaceID
和BreedID
都表示在 中Animal2
。为了防止RaceID
inAnimal2
和 aBreedID
之间的不匹配RaceID
,我在两者上都添加了一个 FK,RaceID, BreedID
它引用了Breed
表中这些字段的 UNIQUE CONSTRAINT。我通常鄙视将 FK 指向 UNIQUE CONSTRAINT,但这是为数不多的这样做的正当理由之一。UNIQUE CONSTRAINT 在逻辑上是一个“备用键”,这使得它对此用途有效。另请注意,该Breed
表仍然有一个 PKBreedID
。BreedID
在RaceID
.BreedID
,因此仍然可以在Breed
没有RaceID
可用的情况下引用 的特定值。Breed
(这也是我更喜欢Race
-specificBreed
表的原因)。Breed
都具有相同的属性。在这个模型中没有简单的方法在Dog
“品种”和Elephant
“品种”之间具有不同的属性。但是,仍然有一种方法可以做到这一点,这在“最终编辑”部分中有说明。Breed
以上的种族中分享一个。我不确定这是否是可取的(或者可能不是在动物的概念中,但可能在其他使用这种类型模型的情况下),但在这里是不可能的。最终编辑(希望 ;-)
Breed
使用相同的子类/继承概念,但作为主要实体。在此设置中,表格将具有所有类型的通用属性(就像表格一样),并表示表格的类型(与表格中的相同)。然后,您将拥有子类表,例如、等。对于较小的项目,这可能被认为是“过度设计”,但它被认为是可以从中受益的情况的一种选择。Breed
Breed
Breed
Animal
RaceID
Breed
Animal
BreedCat
BreedDog
对于这两种方法,有时将视图创建为完整实体的快捷方式会有所帮助。例如,考虑:
CreatedDate
将向表中添加一个字段Animal
。在任何子类表(例如)中都不需要此字段,AnimalCat
因为为两个表插入的行应该在事务中同时完成。LastModifiedDate
字段将被添加到Animal
表和所有子类表中。仅当更新该特定表时,此字段才会更新:如果更新发生在AnimalCat
但不是Animal
针对特定的AnimalID
,则只会设置LastModifiedDate
字段 inAnimalCat
。First off, you are doing well to distinguish between ER modeling and relational modeling. Many newbies don't.
Here are some buzzwords you can use to look up helpful articles on the web.
Your case is a classic case of class/subclass or, if you like, type/subtype.
The phrase that's used in ER modeling is "generalization/specialization". And many of the articles show this under something called EER (Enhanced Entity-Relationship) modeling. This wasn't in Peter Chen's original presentation of ER modeling. It was added later. For a pretty good summary of gen/spec in pdf form, click here
Next, when converting a class/subclass case to relational modeling you design tables. There is more than one approach. The two main approaches are called single table inheritance and class table inheritance. Each has advantages and drawbacks. The best presentation of these two designs comes from Martin Fowler. You can see his outline here and here.
The big advantage of single table inheritance is simplicity. It's all stored in one table. The big drawback is a lot of NULLS. This can waste space and time and result in confusing logic.
类表继承需要连接,但它们既简单又快速。特别是如果您使用一种称为共享主键的技术,其中子类表中的 PK 是超类表中 PK 的副本。您可以为每个连接超类数据和子类数据的子类创建视图。
最后,这个区域有一个标签,可以将像你这样的问题收集在一起。
这是: 子类型
我认为可能的设计为
桌子
Race
桌子
Breed
桌子
Animal
上面的这些 PK 将是自动递增的列。表中的其他列
Animal
可以相应命名。你现在的方法还不错。但是,如果您稍后要添加更多种族(鸟类、鱼类等),那么为每个种族创建单独的表格可能会很麻烦。我会推荐如下内容:
据我了解,一个品种应该只有一个种族。因此,如果您将品种存储在动物表中,您将能够通过加入品种表来确定种族。显然,根据需要将任何其他属性(名称、描述等)添加到 Breed 和 Race 表。