外键引用复合表
Posted
技术标签:
【中文标题】外键引用复合表【英文标题】:Foreign key referencing composite table 【发布时间】:2008-11-06 14:02:41 【问题描述】:我有一个表结构,我不确定如何创建最好的方法。
基本上我有两个表,tblSystemItems 和 tblClientItems。我有第三个表,其中有一列引用“项目”。问题是,此列需要引用系统项或客户端项——哪个都没有关系。系统项的键在 1..2^31 范围内,而客户端项的键在 -1..-2^31 范围内,因此永远不会有任何冲突。
每当我查询项目时,我都是通过在两个表的内容之间执行 UNION ALL 的视图来完成的。
因此,最理想的情况是,我希望将外键引用作为视图的结果,因为视图将始终是两个表的联合 - 同时仍保持 ID 唯一。但我不能这样做,因为我无法引用视图。
现在,我可以删除外键,一切都很好。但是,我真的很想有一些参考检查和级联删除/设置 null 功能。除了触发器,还有什么方法可以做到这一点?
【问题讨论】:
看在 Pete 的份上,请停止使用“TBL”为表名添加前缀。这既恶心又恶心,同时又令人恐惧 【参考方案1】:抱歉回复晚了,我遇到了严重的周末炎。
至于使用第三个表来包含来自客户端和系统表的 PK - 我不喜欢这样,因为这会使同步过于复杂,并且仍然需要我的应用知道第三个表。
出现的另一个问题是我有第三个表需要引用一个项目——无论是系统还是客户端,都没有关系。将表分开基本上意味着我需要有两列,一个 ClientItemID 和一个 SystemItemID,每个列都有一个可以为空的表的约束 - 相当难看。
我最终选择了不同的解决方案。整个问题在于轻松地将新系统项同步到表中,而不会弄乱客户端项,避免冲突等等。
我最终只创建了一个表 Items。 Items 有一个名为“SystemItem”的位列,它定义了显而易见的内容。在我的开发/系统数据库中,我将 PK 作为一个 int 身份(1,1)。在客户端数据库中创建表后,标识键更改为 (-1,-1)。这意味着客户端项目是负面的,而系统项目是积极的。
对于同步,我基本上会忽略 (SystemItem = 1) 的任何内容,同时使用 IDENTITY INSERT ON 同步其余内容。因此,我能够在完全忽略客户端项目并避免冲突的同时进行同步。我还可以仅引用一个涵盖客户端和系统项目的“项目”表。唯一要记住的是修复标准集群键,使其下降以避免客户端插入新项目时的各种页面重组(客户端更新与系统更新的比例为 99%/1%)。
【讨论】:
【参考方案2】:您可以为引用项目的表创建一个唯一 id(db 生成 - 序列、autoinc 等),并创建两个附加列(tblSystemItemsFK 和 tblClientItemsFk)您分别引用系统项和客户端项的位置 - 一些 数据库允许您拥有一个 可为空 的外键。
如果您使用的是 ORM,您甚至可以仅根据列信息轻松区分客户端项和系统项(这样您就不需要负标识符来防止 ID 重叠)。
使用更多的 bakcground/context 可能更容易确定最佳解决方案。
【讨论】:
只有 一些 数据库允许您拥有空外键?只有 一些 数据库也允许您进行 OUTER JOIN 吗?【参考方案3】:您可能需要一个表,例如 tblItems,它只存储两个表的所有主键。插入项目需要两个步骤,以确保在将项目输入到 tblSystemItems 表时,将 PK 输入到 tblItems 表中。
然后第三个表有一个到 tblItems 的 FK。在某种程度上 tblItems 是其他两个项目表的父项。要查询一个项目,有必要在 tblItems、tblSystemItems 和 tblClientItems 之间创建一个 JOIN。
[EDIT-for comment below] 如果 tblSystemItems 和 tblClientItems 控制自己的 PK,那么您仍然可以让他们。您可能会先插入 tblSystemItems,然后再插入 tblItems。当您使用 Hibernate 之类的工具实现继承结构时,您最终会得到类似的结果。
【讨论】:
但是当我将更改推送到 tblSystemItems 表时,我会很麻烦地同步包含 tblItems 表的 PK。理想情况下,我希望 tblSystemItems 表完全独立于客户端项目工作。【参考方案4】:添加一个名为 Items 的表,其中包含一个 PK ItemiD,以及一个名为 ItemType = "System" 或 "Client" 的单列,然后 ClientItems 表 PK(名为 ClientItemId)和 SystemItems PK(名为 SystemItemId)也都是 Items 的 FK。 ItemId,(这些关系是零对一的关系(0-1)
然后在引用项目的第三个表中,只需让它的 FK 约束引用这个额外(项目)表中的 itemId...
如果您使用存储过程来实现插入,只需让插入项目的存储过程首先在 Items 表中插入一条新记录,然后使用该表中自动生成的 PK 值将实际数据记录插入SystemItems 或 ClientItems(取决于它是)作为同一个存储过程调用的一部分,使用系统插入到 Items 表 ItemId 列中的自动生成(身份)值。
这称为“子类化”
【讨论】:
【参考方案5】:我一直对你的桌子设计感到困惑。我不确定它是否正确。我意识到第三个表可能只是提供详细信息,但我不禁想到主键实际上是您的 ITEM 表中的一个,而 FOREIGN 键是您的系统和客户端项目表中的键。然后,您只需要从 Item 到系统和客户端项目表进行正确的外部连接,所有约束都可以正常工作。
【讨论】:
【参考方案6】:我正在使用的数据库中有类似的情况。我在每个称为 EntityID 的表上都有一个“候选键”。然后,如果有一个表需要引用多个其他表中的项目,我使用 EntityID 来引用该行。我确实有一个 Entity 表来交叉引用所有内容(因此 EntityID 是 Entity 表的主键,而所有其他 EntityID 都是 FK),但我发现自己并不经常使用 Entity 表。
【讨论】:
以上是关于外键引用复合表的主要内容,如果未能解决你的问题,请参考以下文章