如何引用另一个表中最初未知的表映射

时间:2015-02-24 16:10:15

标签: database-design

我有四个表:ExternalNameInternalNameExternalInternalNameMapTransaction
ExternalName和InternalName有多对多关系。 ExternalInternalNameMap是ExternalName和InternalName之间的联结表。

约束是:

  • 一个Transaction只能有一个ExternalName和一个与之关联的InternalName。
  • ExternalName可以有很多交易。
  • InternalName可以有很多交易。

因此,ExternalInternalNameMap可以有许多事务,而事务只能对应一个ExternalInternalNameMap。

enter image description here

Transaction表必须连接到其他表,以便ExternalName和InternalName可以与Transaction关联。

在Transaction表中将ExternalInternalNameMap.Id作为外键似乎是一种自然的选择,但是当最初将一行添加到Transaction表时,只有ExternalName是已知的。稍后,用户将ExternalName映射到InternalName。只有这样我们在ExternalInternalNameMap中才有一行。用户需要查看事务数据以了解如何将ExternalName映射到InternalName。

选项A
事务可以有一个fk到ExternalInternalNameMap但InternalNameId(在该表中)最初将为NULL。在这种情况下,我们无法在该表中强制执行重复的InternalNameId和ExternalNameId组合。

选项B
事务可以包含到ExternalName的fk和到InternalName的fk(最初为NULL)。但是,在这种情况下,数据库不会强制Transaction包含有效的ExternalName和InternalName映射。

是否有其他方法可以解决这些问题?

修改:修正图

3 个答案:

答案 0 :(得分:1)

我建议将A和B组合使用。

enter image description here

要在数据库设计级别强制实施完整性约束,您需要在联结表上使用复合主键 ExternalInternalNameMap的PK为{EN_ID, IN_ID}
ExternalInternalNameMap表脉冲内有一个Transaction的可选外键,检查约束将导致一致性。

Transaction table = {FK_EN_ID, FK_EINM_EN_ID, FK_EINM_IN_ID, ...}

检查Transaction table =

上的约束
{FK_EINM_EN_ID is null OR (FK_EINM_EN_ID = FK_EN_ID)}

答案 1 :(得分:1)

一种可能的方法是引入“未知”的概念。内部名称。 对于每个外部名称,您还会在ExternalInternalNameMap中引入一条记录,将该外部名称映射到一个特殊的内部名称'未知'。因此,对于每个外部名称,(最多)一个这样的'未知'映射存在。

基本上,只需遵循方法A.当您创建交易时,请参阅“未知”'映射适当的外部名称。一旦知道了内部名称,就更新事务;使其引用ExternalInternalNameMap中包含“完整”字样的记录。映射。

注意我们在这里引入重复映射;您可以对组合(ExternalNameId, InternalNameId)设置唯一约束。

可能的变化:

  • 而不是专门的记录'未知'表InternalName中的(或' TBD'或其他),您也可以决定在表ExternalInternalNameMap中使用NULL引用。这确实要求列InternalNameId可以为空。
  • 您可以创建“未知”'预先映射(对于表ExternalName中的每个记录,ExternalInternalNameMap中只有一条记录将外部名称映射到“未知”,或者您可以创建“'”。未知'在您需要时进行映射(除非它已经存在),即在创建事务时。

答案 2 :(得分:0)

FOREIGN KEYS无法解决所有问题;暂时忘掉他们......

当出现新的交易时:

  1. 如果这些名称尚未插入内部和/或外部,则插入 存在
  2. 如果关系尚不存在,则插入地图
  3. 插入交易。
  4. 请注意,通过按此顺序执行这三个步骤,您始终可以确保在与它建立FK关系之前存在一行。 (哎呀 - 为什么要声明FK?)

    所以,我想我正在为选项A投票。

    请记住,无论何时需要从Transaction进入Internal,您都需要浏览Map - 这是两个JOIN。并且,类似地,2个JOIN朝另一个方向前进。所以,请确保每个方向都有INDEX。 (FK在一个方向上生成索引。)