不知道如何将变量实体转换为关系表


9

简介和相关信息:

以下示例说明了我面临的问题:

动物有种族,可以是可以是暹罗语波斯语可以是德国牧羊犬拉布拉多犬

动物是一个强大的实体,而其种族是可以具有两个提供的值(猫或狗)之一的属性。 这两个值都很复杂(我在这里仅添加了dog / cat的类型来说明问题,但也可能有cat / dog的名字和其他东西)。

问题:

我不知道如何为该示例创建关系表。

我为解决问题所做的努力:

我尝试使用Chen的符号来绘制ER图,该图代表了问题,但作为一个初学者,我不知道我是否做对了。这是我得到的:

在此处输入图片说明

如果我画错了,我深表歉意,如果是的话,请纠正我。我不仅希望获得“免费的解决方案”,而且希望学习如何处理该问题,以便将来自己解决。

我唯一想到的就是创建两个单独的表,一个用于猫,一个用于狗。同样,“ 动物”表中的“ 种族”属性将仅存储狗的值。像这样:

Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >

我对解决方案确实感觉很不好,我担心这是错误的,因此出现以下问题。

问题:

  • 如何将示例转换为ER图?
  • 如何将ER图转换为关系表?

如果需要更多信息,请发表评论,我将尽快更新我的帖子。也可以随意添加适当的标签,因为我在这里还很陌生。

谢谢。


1
EER图到表的转换可以在1986年的TJTeorey,D.Yang,JPFry中找到:使用扩展实体关系模型的关系数据库逻辑设计方法。它很简单,也是我最喜欢的论文之一。
miracle173

Answers:


11

此方案的正确结构是SubClass / Inheritance模型,并且与我在此答案中提出的概念几乎相同:值的异类排序列表

这个问题中提出的模型实际上非常接近,因为该Animal实体包含类型(即race)和所有类型共有的属性。但是,需要进行两个较小的更改:

  1. 从它们各自的实体中删除Cat_ID和Dog_ID字段:

    这里的关键概念是,一切Animal,不管raceCatDogElephant,等等。在此出发点的情况下,由于以下原因raceAnimal并不需要任何特定的标识符:

    1. Animal_ID是独特的
    2. CatDog和任何其他race在未来加入的实体不这样做,由自己,完全代表任何特定的Animal; 仅当与父实体中包含的信息结合使用时,它们才有意义Animal

    因此,在Animal_ID产权的CatDog等实体既是PK和FK回Animal实体。

  2. 区分以下类型breed

    即使两个属性共享相同的名称,也不一定意味着这些属性是相同的,即使名称相同也暗示了这种关系。在这种情况下,您真正​​拥有的实际上是CatBreedDogBreed单独的“类型”

最初的笔记

  1. SQL特定于Microsoft SQL Server(即T-SQL)。意思是,请注意数据类型,因为所有RDBMS的数据类型都不相同。例如,我正在使用,VARCHAR但是如果您需要存储标准ASCII集之外的任何内容,则应该使用NVARCHAR
  2. “类型”表(RaceCatBreedDogBreed)的ID字段不是自动递增的(即T-SQL的IDENTITY),因为它们是应用程序常量(即它们是应用程序的一部分),它们是数据库,并enum以C#(或其他语言)表示为。如果添加值,则会在受控情况下添加它们。我保留通过应用程序输入的用户数据使用自动递增字段的功能。
  3. 我使用的命名约定是为每个子类表命名,从主类名开始,然后是子类名。这有助于组织表并清楚地指示(无需查看FK)子类表与主实体表之间的关系。
  4. 请参阅最后的“最终编辑”部分,以获取有关视图的注释。

“品种”作为“种族”特定方法

繁殖为种族专用图
第一组表是查找/类型表:

CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE CatBreed
(
  CatBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  CatBreedAttribute1 INT,
  CatBreedAttribute2 VARCHAR(10)
  -- other "CatBreed"-specific properties as needed
);

CREATE TABLE DogBreed
(
  DogBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  DogBreedAttribute1 TINYINT
  -- other "DogBreed"-specific properties as needed
);

第二个清单是主要的“动物”实体:

CREATE TABLE Animal
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  Name VARCHAR(50)
  -- other "Animal" properties that are shared across "Race" types
);

ALTER TABLE Animal
  ADD CONSTRAINT [FK_Animal_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

这第三组表是免费的子类实体完成每个定义RaceAnimal

CREATE TABLE AnimalCat
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  CatBreedID INT NOT NULL, -- FK to CatBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Cat"-specific properties as needed
);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_CatBreed]
  FOREIGN KEY (CatBreedID)
  REFERENCES CatBreed (CatBreedID);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);


CREATE TABLE AnimalDog
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  DogBreedID INT NOT NULL, -- FK to DogBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Dog"-specific properties as needed
);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_DogBreed]
  FOREIGN KEY (DogBreedID)
  REFERENCES DogBreed (DogBreedID);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);

breed在“其他说明”部分之后显示使用共享类型的模型。

补充笔记

  1. 的概念breed似乎是混乱的焦点。jcolebrand提出(在问题中进行评论)建议,这breed是一个跨不同races 共享的属性,而其他两个答案也将其整合到了它们的模型中。但是,这是一个错误,因为的值breed未在的不同值之间共享race。是的,我知道另外两个提议的模型都试图通过使成为race的父代来解决此问题breed。虽然从技术上解决了关系问题,但这无助于解决关于不常见属性该怎么办的整体建模问题,也无助于解决race不具有的属性的整体建模问题breed。但是,在保证此类属性存在于所有情况下的情况下Animals,我还将为此提供一个选项(如下)。
  2. vijayp和DavidN提出的模型(看起来相同)不起作用,因为:
    1. 他们要么
      1. 不允许存储非公共属性(至少不允许存储任何的单个实例Animal),或者
      2. 要求将所有的所有属性都race存储在Animal实体中,这是一种非常扁平(几乎是非关系)的表示此数据的方式。是的,人们一直在这样做,但这意味着每行有很多NULL字段用于不适合该特定属性的属性,并且race知道每行哪些字段与该race记录的特定内容相关联。
    2. 他们不允许添加raceAnimal在没有未来breed的财产。即使ALL Animal都具有a breed,也不会因先前提到的内容而改变结构breedbreed依赖于race(即breedfor Cat不同于breedfor Dog)。

“繁殖”为共同/共享财产方式

在此处输入图片说明
请注意:

  1. 下面的SQL可以在与上述模型相同的数据库中运行:

    1. Race表是相同的
    2. Breed表是新
    3. 这三个Animal表都附加了一个2
  2. 即使Breed是现在的共同财产,似乎也没有Race在主要/母公司中注明(即使从技术上讲是正确的)。因此,RaceIDBreedID均以表示Animal2。为了防止RaceIDin Animal2和a 之间的不匹配BreedID,对于另一个RaceID,我在两者上均添加了FK,该FK RaceID, BreedID引用了Breed表中这些字段的UNIQUE CONSTRAINT 。我通常不喜欢将FK指向UNIQUE CONSTRAINT,但这是这样做的几个有效理由之一。从逻辑上说,UNIQUE CONSTRAINT是“备用键”,因此对于此用途有效。另请注意,该Breed表格的PK仍为BreedID
    1. 之所以没有在组合字段上仅使用PK且没有UNIQUE CONSTRAINT的原因是,它允许BreedID在的不同值上重复相同的内容RaceID
    2. 不切换PK和UNIQUE CONSTRAINT的原因是,这可能不是的唯一用法BreedID,因此在Breed没有RaceID可用值的情况下,仍然应该可以引用特定值。
  3. 尽管以下模型可以正常工作,但是它在共享的概念方面存在两个潜在的缺陷Breed(这就是为什么我偏爱Race-specific Breed表)。
    1. 有一个隐含的假设,即的ALL值Breed具有相同的属性。在此模型中,没有简单的方法可以在Dog“品种”和Elephant“品种” 之间具有完全不同的属性。但是,仍有一种方法可以做到这一点,请参见“最终编辑”部分。
    2. 无法共享一个Breed以上的种族。我不确定这样做是否可取(或者也许不是在动物概念上,但在其他可能使用这种模型的情况下),但是在这里是不可能的。
CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY,
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE Breed
(
  BreedID INT NOT NULL PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  BreedName VARCHAR(50)
);

ALTER TABLE Breed
  ADD CONSTRAINT [UQ_Breed]
  UNIQUE (RaceID, BreedID);

ALTER TABLE Breed
  ADD CONSTRAINT [FK_Breed_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

CREATE TABLE Animal2
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race, FK to Breed
  BreedID INT NOT NULL, -- FK to Breed
  Name VARCHAR(50)
  -- other properties common to all "Animal" types
);

ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

-- This FK points to the UNIQUE CONSTRAINT on Breed, _not_ to the PK!
ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Breed]
  FOREIGN KEY (RaceID, BreedID)
  REFERENCES Breed (RaceID, BreedID);


CREATE TABLE AnimalCat2
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalCat2
  ADD CONSTRAINT [FK_AnimalCat2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);

CREATE TABLE AnimalDog2
(
  AnimalID INT NOT NULL PRIMARY KEY,
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalDog2
  ADD CONSTRAINT [FK_AnimalDog2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);


最终编辑(希望;-)

  1. 关于处理类型之间不同的性能的可能性(然后难度)Breed,它能够使用相同的子类/继承的概念,但与Breed作为主要实体。在此设置中,Breed表格将具有所有类型的属性Breed(就像Animal表格一样),RaceID并表示类型Breed(与Animal表格中的相同)。然后,你将有子表,如BreedCatBreedDog等。对于较小的项目,这可能被认为是“过度工程”,但它被提及是可以从中受益的情况的一种选择。
  2. 对于这两种方法,有时都有助于将视图创建为完整实体的快捷方式。例如,考虑:

    CREATE VIEW Cats AS
       SELECT  an.AnimalID,
               an.RaceID,
               an.Name,
               -- other "Animal" properties that are shared across "Race" types
               cat.CatBreedID,
               cat.HairColor
               -- other "Cat"-specific properties as needed
       FROM    Animal an
       INNER JOIN  AnimalCat cat
               ON  cat.AnimalID = an.AnimalID
       -- maybe add in JOIN(s) and field(s) for "Race" and/or "Breed"
  3. 尽管不是逻辑实体的一部分,但是在表中具有审计字段以至少了解何时插入和更新记录是很普遍的。因此,实际上:
    1. 一个CreatedDate字段将被添加到Animal表中。在任何子类表(例如AnimalCat)中都不需要此字段,因为为两个表插入的行应在事务中同时完成。
    2. 一个LastModifiedDate字段将被添加到Animal表和所有子类表中。如果某个表被更新此字段只获取更新:如果发生在更新AnimalCat,但不是Animal为特定的AnimalID,那么只有LastModifiedDate在现场AnimalCat将设置。

2
我不知何故感觉到您完全了解我的问题所在。我将给您链接的答案一个外观,并仔细研究它。只需对表进行简单定义就可以了(如果您现在无法编写太多的SQL查询)。如果您决定使用SQL查询或表定义来更新您的帖子,请给我评论。再次感谢你。最好的祝福。
AlwaysLearningNewStuff 2014年

1
我正在尝试将您的答案应用于我的现实生活中。如果我盲目地遵循您的指示,我相信我可能会错过进一步优化设计的机会。由于您已经能够完全理解我的问题并提供出色的答案,所以我希望您看一下我的最新问题。我已经组成了使用通用数据模型的问题,以便也对将来的读者有用。如果您找不到它,请给我留言。谢谢您,抱歉打扰您……
AlwaysLearningNewStuff,2016年

@AlwaysLearningNewStuff您好。较早收到此消息,但没有时间立即得到它。通过单击上方的您的名字,我可以找到新的问题,它显示了您所有的问题:-)。
所罗门·鲁兹基

我指的是这个问题。简而言之:我有3个具有common属性的实体D,因此我想从您的答案中应用方法。两个实体具有E第三个实体中不存在的公共属性。我应该忽略这一事实并应用标准解决方案,还是有办法进一步优化设计?
AlwaysLearningNewStuff '16

4

首先,您可以很好地区分ER建模和关系建模。许多新手没有。

您可以使用以下流行语在网络上查找有用的文章。

您的案例是类/子类的经典案例,或者,如果您愿意,则是类型/子类型。

ER建模中使用的短语是“一般化/专业化”。许多文章在称为EER(增强实体关系)建模的情况下展示了这一点。这不是Peter Chen最初提出的ER建模。它是后来添加的。有关pdf格式的gen / spec的很好的总结,请单击此处

接下来,将类/子类案例转换为关系建模时,您将设计表。有不止一种方法。两种主要方法称为单表继承和类表继承。每个都有优点和缺点。这两种设计的最佳展示来自Martin Fowler。您可以在这里这里看到他的轮廓。

单表继承的最大优点是简单。全部存储在一个表中。最大的缺点是有很多NULL。这会浪费时间和空间,并导致逻辑混乱。

类表继承需要联接,但是它们简单,快速。特别是如果您使用一种称为共享主键的技术,其中子类表中的PK是超类表中PK的副本。您可以为将超类数据与子类数据连接在一起的每个子类创建视图。

最后,在此区域中有一个标签,可收集您一样的问题。
它是:


1
+1使我感到困惑的是,表图中缺少主键。尤其是在“ classTableInheritance”中,我看不到所有这些表都是通过相同的主键连接的。
miracle173

@ miracle173有效点。由于某种原因,Fowler在图中未包括PK和FK。类表继承下还有其他文章提供了此详细信息。并非所有类表继承的实现都将其与共享主键结合在一起。我推荐它。在插入时需要做更多的工作,但是在联合检索时会更加轻松快捷。
Walter Mitty 2014年

3

我认为可能的设计是

Race

RaceId- PK- Int
RaceName - Varchar(50)

Breed

BreedId - PK- Int
RaceId - FK - Int
BreedName - varchar(50)

Animal

AnimalId - PK- Int
BreedId - FK - Int
Other Columns....

上面的这些PK为自动递增列。表中的其他列Animal可以相应地命名。

在此处输入图片说明


另外,我将在Animal表中添加一个带有Race和Type键(可能是触发器)的字段,以便于以后的索引提高速度。
Felipe Alcacibar 2014年

0

您当前的方法还不错。但是,如果以后要添加更多的种族(鸟,鱼等),则为每个种族创建单独的表可能很麻烦。我建议类似以下内容:

Animal < # Animal_ID, Breed_ID, other attributes >
Breed < # Breed_ID, Race_ID >
Race < # Race_ID >

以我的理解,一个品种应该只有一个种族。因此,如果您将品种存储在“动物”表中,则可以通过加入“品种”表来确定种族。显然,根据需要将任何其他属性(名称,描述等)添加到“品种”和“种族”表中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.