【问题标题】:Sql Server - Foreign key referencing multiple columns one of which isn't in the source tableSql Server - 引用多列的外键,其中一列不在源表中
【发布时间】:2011-06-30 14:04:19
【问题描述】:

我的外键有问题。这是我的数据库结构(简化):

表“语言”

LanguageID - primary key
LanguageName - string (for example 'English')
..

表“用户”

UserID - primary key
LanguageID - byte (FK to Languages.LanguageID)
..

表“本地化”

LocalizationID - / compound primary key
LanguageID     - \ compound primary key (FK to Languages.LanguageID)
Data - string (for example 'My Program' in English)

表“用户本地化”

UserLocalizationID - primary key
UserID - which user (FK to Users.UserID)
..
some other useful columns -> this table cannot be removed **EDITED**
..
LocalizationID - what string (FK to Localization.?) <- oops, not really because 
                                                       LanguageID is needed 
                                                       for FK to 'Localization' 

如何在“用户本地化”到“本地化”中进行 FK(或任何其他完整性检查)。这种配置有可能吗?还是不行,因此需要进行一些重组(真的吗?)?如果有怎么实现?

编辑:为了更清晰,稍微整理了一下。

【问题讨论】:

  • 清理引用——你有表 A/B/C,但你有关于命名表(字符串、语言等)的 FK 的注释。
  • 嗨,'string' 和 'language' 表不是这个场景中的表,它们是这个范围之外的 FK。我已经给他们添加了一个注释。忽略它们。
  • 我的猜测是,您需要表 C 中的另一个字段(类型)和引用表 B 的(复合)主键的复合外键 (ID_B, Type)
  • 最好向我们展示表的名称,以便我们更好地理解结构以及是否需要进一步规范化。
  • 嗯,有没有办法不存储重复信息。我真的不想在这个表中存储语言,它只是冗余数据。还有其他方法吗?这个链接表会很大,我尽量保持低。 TableA.Type 和 TableC.Type(建议)之间的同步也会很复杂。

标签: sql sql-server database-design foreign-keys


【解决方案1】:

简单的答案是:如果你的桌子Localization 是这样的:

LocalizationID - / compound primary key
LanguageID     - \ compound primary key (FK to Languages.LanguageID)
Data - string (for example 'My Program' in English)

并且您想将外键添加到引用该表的另一个表中,该外键需要在手边有您的 PK 的 两列,所以它可能是:

表“用户本地化”

UserLocalizationID - primary key
UserID - which user (FK to Users.UserID)
(LocalizationID, LanguageID) - FK to Localization

这是复合主键的缺点之一 - 任何引用它们的 FK 还必须包含复合 PK 的 all 列 - 没有例外/技巧/变通方法。有两列,这仍然是可行的,但是有四、五、十列,它变得非常混乱。这也意味着该表的任何JOIN 都必须包含所有公共字段 - 再说一次,有两个仍然可以,但如果有更多,它会变得非常混乱。

这是我经常考虑向只有复合 PK 的表添加人工代理键​​的原因之一 - 只是为了简化对其的 FK 连接。

【讨论】:

  • 您好,我选择这种方式是因为我想减轻 'UserLocalization' 表的负载。出于性能原因,我想消除加入“本地化”表的需要。原因是表“语言”仅包含 3 行(固定)。所以只有 3 个可能的 LanguageID 和 30 个可能的 LocalizationID(也是固定的)。因此,整个“本地化”表是固定的。此外,“UserLocalization”表将包含数十亿条记录。如果我将独立的唯一键(一列)放入“本地化”,则无论何时从“用户本地化”中选择,都需要一个 - 否则完全可以 - 加入。
  • 如果可以使持久计算列类似于:ComputedLanguageID as (select u.LanguageID from Users u where u.UserID = UserID)。因为那里有钥匙,只有一跳。 :D
  • 如果您的数据库中的其他表很小,那么我不会担心在此阶段执行连接的性能。如果以后发现它很慢,那么您可以考虑使用索引视图。
  • 我猜你是对的。我正在考虑物化视图,但没关系。我吓坏了,因为这是一个潜在的瓶颈。
【解决方案2】:

摆脱UserLocalization 表。请改用此 SQL 来查找用户的本地化字符串:

SELECT * FROM Users INNER JOIN Localization ON Users.LanguageID = Localization.LanguageID

所有使用相同语言的用户都需要/拥有相同的本地化记录,因此您无需再添加任何完整性检查;您已经在 UsersLocalization 表中对 LanguageID 上的 FK 进行了所有检查。

如果您想查找特定用户的本地化数据/字符串,只需在 SQL 末尾添加 WHERE UserID = [Whatever]

【讨论】:

  • 您好,很遗憾,UserLocalizaton 包含更多数据。以状态为例。我想我应该在问题中说清楚,但我没有想到有人会完全优化表格。但这肯定是我最初发布的场景的解决方案。我将编辑问题以减少混乱。
猜你喜欢
  • 2011-03-11
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 2010-12-16
  • 2016-03-09
  • 2010-10-03
相关资源
最近更新 更多