为什么多对多数据结构需要两个额外的表?

时间:2009-07-26 21:39:44

标签: database data-structures many-to-many one-to-many

此问题基于the thread

如果我们有一对多的数据结构,我们需要一个“帮助表”来存储一个人的电话号码。很多人不能拥有相同的电话号码。

我期待着为什么我们需要在多对多关系之间需要两个“帮助表”的解释。一个例子是问号网站,许多用户可以添加相同的标签:

alt text http://files.getdropbox.com/u/175564/db/db-55.png

为什么我们需要使用表格Question-Tag-xrefQuestion-Tags

为什么我们不能只为标签设置一个表格如下?

   Question_id   |    tag
   1                  C 
   1                  C++
   2                  Java
   2                  C

为什么两个不同的问题具有相同的标签是计算机的问题?

7 个答案:

答案 0 :(得分:4)

这只是一张“额外”的表格。

这是因为同一个问题可能有很多标签。

因为很多问题都可能使用相同的标签。

您需要存储的地方(questionId,tagId)并确保没有重复的内容。


我没有关注过这个主题的问题,但看起来这里有一些糟糕的设计。我以为你只有一张额外的桌子因为我认为你有一个合理的结构。你没有。

为什么Question-Tags同时包含标签字符串和标签ID?这对我来说没什么意义。


我不想回过头来回答一系列问题。不过,我想试着说明我在说什么。所以我使用NORMA工具为StackOverflow的这一部分创建了一个非常简单的对象 - 角色建模模型:

Simple model of StackOverflow

这生成了以下ER图:

ER diagram

请注意,我们需要为标记保留“额外”表格,因为没有关于标记的其他信息。此外,不需要将标记ID存储为Tags表的外键,因为标记名称已经是唯一的。如果我们保留有关标记的其他数据,那么可能会有一个单独的Tags表,主键仍然是标记名。如果它成为性能问题,可以更改为使用整数id,在这种情况下,标记名称仍将获得唯一索引。

答案 1 :(得分:4)

这是normalization的问题。恕我直言,关于这个主题的最佳书籍之一是Joe Celko's SQL for Smarties。基本上,你避免了所谓的“异常”。在您的示例中,如果我使用“Java”标记删除所有问题,我将永远无法知道我曾经有过一个名为“Java”的标记(删除异常)。破解表格也很重要,因为您需要使用外部参照表来描述主体之间关系的属性。

答案 2 :(得分:1)

http://en.wikipedia.org/wiki/Database_normalization

这不是计算机的问题,但是RDBMS理论说,db应该通过规范化减少信息重复。 以下是Codd博士所说的关于正常化需求的内容:

  1. 从不受欢迎的插入,更新和删除依赖项中释放关系集合;
  2. 随着新类型数据的引入,减少重建关系集合的需要,从而延长应用程序的使用寿命;
  3. 使关系模型对用户更具信息性;
  4. 使查询统计数据的关系集合中立,这些统计数据随着时间的推移可能会发生变化。
  5. E.F。 Codd,“数据库关系模型的进一步规范化”

答案 3 :(得分:1)

问题在于您希望表结构的规范化程度。通常,您不希望将信息存储在多个位置。为此,当可以对许多项重复数据时,将其标准化 - 将该数据移动到单独的表中,其他表中的多行可以通过存储数据的键而不是数据本身来引用它。当您有许多行共享相同的数据 AND 时,您想要将其标准化,您需要一个中间表来存储表之间的关系(引用对)。

答案 4 :(得分:1)

在关系数据库中,许多关系被实现为两个互易的一对多关系,每个关系都需要一个额外的表(在直接表示实体的表之外)来实现。

  • 首先,第一个表中的行与第二个表中的多个行之间存在一对多的关系。
  • 第二,第二个表的一行与第一个表中的许多行之间的另一个多关系。

它的原因与relational database model

有关

答案 5 :(得分:1)

只是为了补充别人说的话(我不会重复他们的评论)

根据我的经验,它通常不是一个帮助表,而是一个连接表。通常,您处理的事情比简单的关键字更复杂。 'extra'表模拟了其他两个实体之间的关系。

另一个例子可能是我有许多收件人联系人的营销活动。这两个实体都不依赖于另一个。任何特定广告系列都会有多个联系人,任何联系人都可能会收到多个广告系列。在这种情况下,联接表会模拟发送者的历史记录。

Campaign 
 - CampaignID (PK)
 - other columns

Contact 
 - ContactID (PK)
 - other columns

CampaignContact
 - CampaignContactID (PK)
 - CampaignID (FK)
 - ContactID (FK)

这与1-many关系(有时称为主 - 细节关系)完全不同。这里有一个典型的例子是Invoice - > InvoiceItems。发票项目专门链接到一个且只有一个父发票。

Invoice
 - InvoiceID (PK)
 - other columns

InvoiceItem
 - InvoiceItemID (PK)
 - InvoiceID (FK)
 - other columns

答案 6 :(得分:0)

通常它比标签列更多信息。因此,如果它是大量信息,那么您有冗余数据(在您的示例中您有2个“C”值)。然后,如果相同的值存在于多个位置,则更新将成为问题。因此规则是数据应该存在于一个位置,并且其ID在其他地方用于引用它。然后当你更新它时,它只需要在一个地方完成。