我有四个表:ExternalName
,InternalName
,ExternalInternalNameMap
和Transaction
。
ExternalName和InternalName有多对多关系。 ExternalInternalNameMap是ExternalName和InternalName之间的联结表。
约束是:
因此,ExternalInternalNameMap可以有许多事务,而事务只能对应一个ExternalInternalNameMap。
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映射。
是否有其他方法可以解决这些问题?
修改:修正图
答案 0 :(得分:1)
我建议将A和B组合使用。
要在数据库设计级别强制实施完整性约束,您需要在联结表上使用复合主键
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无法解决所有问题;暂时忘掉他们......
当出现新的交易时:
请注意,通过按此顺序执行这三个步骤,您始终可以确保在与它建立FK关系之前存在一行。 (哎呀 - 为什么要声明FK?)
所以,我想我正在为选项A投票。
请记住,无论何时需要从Transaction进入Internal,您都需要浏览Map - 这是两个JOIN。并且,类似地,2个JOIN朝另一个方向前进。所以,请确保每个方向都有INDEX。 (FK在一个方向上生成索引。)