何时同时使用外键作为主键?

时间:2018-01-01 16:59:16

标签: mysql sql

我得到了一张中间表ArticleLanguage

idArticleLanguage
ArticleId
LanguageId
Name

外键是:

ArticleId
LanguageId

我应该使用主键:

ArticleId
LanguageId

因为这些字段是相关表中的主键吗?

2 个答案:

答案 0 :(得分:4)

链接/连接表

假设链接表定义为:

CREATE TABLE Article
(
     ArticleId INT PRIMARY KEY
     -- ... other columns
);

CREATE TABLE Language
(
    LanguageId INT PRIMARY KEY
     -- ... other columns
);

根据 @JulioPérez选项1 ,链接表可以创建为:

CREATE TABLE ArticleLanguage
(
    ArticleId INT NOT NULL,
    LanguageId INT NOT NULL,
    Name VARCHAR(50),

   -- i.e. Composite Primary Key, consisting of the two foreign keys.
   PRIMARY KEY(ArticleId, LanguageId),
   FOREIGN KEY(ArticleId) REFERENCES Article(ArticleId),
   FOREIGN KEY(LanguageId) REFERENCES Language(LanguageId)
);

即。复合主键由“链接”关系中使用的两个外键组成,并且根本没有额外的代理键(idArticleLanguage)。

此方法的优点

  • 强制使用链接的唯一性,即同一ArticleIdLanguageId不能多次链接。
  • 在链接表上保存不必要的其他代理键列。

这种方法的缺点:

  • 需要引用此链接表的任何下游表都需要重复两个键(ArticleId, LanguageId)作为复合外键,这将再次消耗空间。涉及引用ArticleLanguage的下游表的查询也可以直接加入ArticleLanguage,可能绕过链接表(通常很容易'忘记'两个键都是必需的在使用外来复合键时的连接中。)

SqlFiddle of option 1 here

备选方案( @JulioPérez选项2 ),是将您的额外代理PK保留在参考表上。

CREATE TABLE ArticleLanguage
(
    -- New Surrogate PK
    idArticleLanguage INT NOT NULL AUTO_INCREMENT,
    ArticleId INT NOT NULL,
    LanguageId INT,
    Name VARCHAR(50),

   PRIMARY KEY(idArticleLanguage),
   -- Can still optionally enforce uniqueness of the link
   UNIQUE(ArticleId, LanguageId),
   FOREIGN KEY(ArticleId) REFERENCES Article(ArticleId),
   FOREIGN KEY(LanguageId) REFERENCES Language(LanguageId)
);

此方法的优点

  • 主键idArticleLanguage比复合键窄,这将有助于引用表ArticleLanguage的任何其他下游表。它还要求下游表通过ArticleLanguage链接表加入以获取ArticleId和LanguageId,以便进一步加入语言和文章表。
  • 该方法允许使用其他用例,即如果可以多次向LanguageArticle添加相同的链接(例如,两次修订或两次重印等),则可以删除UNIQUE键约束

此方法的缺点

  • 如果每篇文章和语言只能有一个唯一链接,那么额外的代理键是多余的

SqlFiddle of option 2 here

如果您要求提供意见,我会坚持使用选项1,除非您在ArticleLanguage表中确实需要非唯一链接,或者除非您有更多下游表格引用{{1} (这将是不寻常的,IMO)。

每个类型/每类继承的表

与OP的帖子无关,但是在引用表中可以将外键用作主键的另一种常见情况是在对面向对象的类层次结构进行建模时采用 Table per Type 方法有多个子类。由于子类和基类表之间的0/1对1关系,基类表的主键也可以用作子类表的主键,例如:

ArticleLanguage

有关TPT和other OO modelling in tables here

的更多信息

答案 1 :(得分:3)

您有两种方式:

1)Put" ArticleId + LanguageId"作为"中间表"中唯一的主键你可以将其命名为" idArticleLanguage"。这被称为"复合"主键,因为它由2个(在其他情况下多于2个)字段组成,在这种情况下是2个外键(PK = FK + FK)。

2)创建" idArticleLanguage"这与其他两个" id"无关。并将其设置为主键。它可以是一个简单的自动增量整数。

两种选择都被接受。您的选举将取决于您想要实现的目标,因为如果您需要在此中间表中添加相同语言(例如Wilkommen德语)会发生什么,因为您有2个不同版本的文章?如果您选择备选1,它将引发错误,因为您将拥有2行相同的复合主键,那么您必须选择备选2并为此表创建完全不同的主键

在任何其他情况下(或目的),您可以选择替代方案1,它将完美地运作

关于问题标题的更改:

  

同时使用外键作为主键?

我将用这个例子来解释它:

你有两张桌子:" country"和" city"。 "国家"拥有世界上所有的国家," city"拥有世界上所有的城市。但你需要了解世界上的每一个资本。你应该怎么做?

您必须创建一个"中间表" (命名为"资本")将拥有世界上的每一个资本。所以,我们知道这个国家有它的主要关键词" idcountry"而城市的主要关键是" idcity"你需要把两个作为外键带到桌子上"资本"因为你需要" city"的数据。和#34;国家"表填写"资本"表

然后"资本"将拥有它自己的主键" idcapital"这可以是复合的" idcity + idcountry"或者它可以是一个自动增量整数,在这两种情况下你必须具有" idcity"和" idcountry"作为你的"资本"的外键表