2017-05-09 47 views
-1

在使用mysql工作台和使用设计器设计数据库时,关系工具使用第三个表格形成2个表格之间的多对多关系。为什么多对多关系使用前一个表中的所有关键字?

我有表

  • TABLE1
  • TABLE2
  • 表3

TABLE2为f从TABLE1的主键oregin键,有多对一关系

TABLE2和表3是尽快使用一个多对多的关系, 为我创造的关系 一个新表TABLE3_has_TABLE2与所有创建相关表2的主键(表2的主键&表1的外键)和TABLE3(表3的主键)。

现在, 为什么有table1的外键。

即使我删除我将能够使用table2作为中间查询table1和table3的数据,所以有这种关系或避免这种情况很好吗?


对于实施例在下面图 这是位置的地理分布,在右侧示出了它的hirarchy。现在 , 表1(区域)是使用STATE_ID & zone_id的 表2(状态)使用zone_id 表3(分割),以表1是有关涉及表2(状态)的主表table1(zone)

问题:这个zone_id列应该在table3中吗?

类似地,table4包含table3的所有以前的键列。

enter image description here

回答

0

它是在关系模型的最佳做法,以避免许多一对多的关系。正如你所看到的那样,工作台通常会补偿尝试这样做的用户。让我们用一个例子(或者检查tl; dr),其中有两个识别的实体;买家和硬件项目。有些人购买1件商品,其他人购买1件以上。问题是,同样的物品可以被很多人购买。所以买家表有A先生买钉子。简单到足以在一行中记录。但是,你看,他起身并获得另一件物品!我们如何证明他购买了另一件物品?

一种方法是在表中添加另一个属性(如“item_number_two”)。但是,他又得到了另一个!我们不能继续添加这样的属性。数据库的设计更多是为了垂直添加记录,而不是水平添加属性(以提供可视图片)。有一个更长的解释,但你应该阅读,或者可能可能会在阅读后找出它。

另一种方法是重新输入A先生的记录,然后在该列中输入另一个项目的ID,表明他购买了两件物品(从数据库的角度看,他不是“他”,而是两个不同的人!)。

更好的方法是创建一个由原始表中找到的唯一标识符组成的表(每个表只需一个)。这被称为中间表。原始表本身没有来自其他表的外键。

这是组合键的概念出现的地方。它意味着两个或多个候选键用于唯一标识一条记录,而不仅仅是一条。这是如何工作的:

Person Table: 
| person_ID | person_Name | 
| P0001 | Mr. A | 
| P0002 | Mr. B | 
| P0003 | Mr. C | 
| P0004 | Mr. D | 

Cat Table 
| item_ID | cat_Name | 
| I0001 | Nails  | 
| I0002 | Screws  | 
| I0003 | Hammers | 
| I0004 | Power-Saw | 

Intermediary table 
| person_ID | item_ID | 
| P0001 | I0001 | 
| P0001 | I0002 | 
| P0001 | I0003 | //Shows that person 1 bought more than one item 
| P0002 | I0004 | 
| P0002 | I0001 | //Shows that an item has been bought by more that one person 

所以这个新表一个表中的记录匹配(通过使用一个主键)到另一个记录。唯一会重复的是两个ID之一。只要没有两个组合重复,就会创建一个独特的记录。如果映射到多对多关系的表格在输入记录时不可避免地浪费了数据库中的空间,因为必须创建相同数据的新记录以显示小的差异(不按比例添加实际值到空间)。另一个问题是,当进行查询时,它会导致更多的计算,浪费时间和空间。或者返回的结果可能是错误的...

编辑: 如果您有表A和B具有多对多关系,请执行以下操作作为替代方法。创建一张表C.从表A和B中取出主键并将它们放在表C中。在表C中它们都以主键和外键的形式存在。这意味着会创建以下关系。

| Table A |-----------<| Table C |>------------|Table B| 

表A和B到C

示例查询链接:

SELECT C.itemID FROM A, C WHERE A.personID = P0001 AND A.personID = C.personID; 

这个查询将返回由人与P0001的ID购买的物品的所有的ID。记录必须符合具有P0001的personID的条件,但所选记录必须在表C(中间表)中具有该匹配的ID。扩展查询可以从表B中获取项目名称.C中的每个属性都具有与表A或B中的键的值对应的记录值,这意味着可以运行查询来提取其他信息,表C中的值=表A/B中的值(取决于你想要的值)。

+0

1.可以使用多对多关系的替代方案? – abhi

+0

我提到的中间表。检查我的编辑。 –

0

严格来说,从非规范化的角度来看,DIVISION.STATE_ZONE_ID不是必需的。

由于您可以通过在state_id上​​加入STATE来从DIVISION中获取ZONE_ID。

这与DISTRICT中的division_state_state_id & division_state_zone_id相同。
拥有division_division_id足够加入DIVISION,然后STATE,然后ZONE。

但是,如果您要删除这些“额外”字段呢?
然后,SQL总是需要经过连接表的级联才能获得ZONE.zone_name。

所以有一个优点,即通过拥有那些'额外'字段,就可以直接加入ZONE表。这可以简化/加快某些流行的查询。

缺点是确保引用完整性变得困难。
因为例如,您可以将不同的zone_id分配给DIVISION.state_zone_id,而不是通过DIVISION.state_state_id可以获得的STATE.zone_id。

+0

谢谢,这就是我也在想,是否有任何方法来确保参照完整性得以维持。因为我遇到了你提到的加入多个表并放慢查询的问题。 – abhi

+0

通常通过涉及表上的[triggers](https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql)完成。例如,当您更新DISTRINCT.division_division_id时,更新触发器会自动从DIVISION中检索正确的zone_id,然后还会更正DISTRINCT.division_state_zone_id。当STATE.zone_id更改时,它会变得更加困难,并且更新后触发器需要相应地更正所有其他表。 – LukStorms

相关问题