【问题标题】:If two tables have a "One To One" relationship, should they have the same column as primary key?如果两个表具有“一对一”关系,它们是否应该具有与主键相同的列?
【发布时间】:2012-06-23 11:20:06
【问题描述】:

假设我有一个名为Users 的表,它代表网站的注册用户。我还有一个AccountActivation 表,它存储发送到新用户电子邮件以验证该电子邮件的随机生成的字符串。

AccountActivation 表有 UserId 列,这也恰好是 Users 表的主键。它还有ActivationCode 列来存储代码。任一列都可以唯一标识AccountActivation 表中的一行。

因此,如果我选择激活码列作为主键,我最终会得到两个具有不同主键的一对一表。我以为在一对一的关系中,两张表必须有相同的主键?

【问题讨论】:

  • 如果你选择ActivationCode作为PK,那么为什么你有两个一对一的关系呢?唯一的关系是AccountActivation.UserId -> Users.UserId - 或者你认为你突然有什么? UsersUserId 上有它的 PK,AccountActivationActivationCode 上有它的 PK - 完全没有问题,没有理由不这样做。
  • 很可能,“UserId”和“ActivationCode”都是 AccountActivation 表的候选键。
  • 你怎么知道同一个随机生成的字符串不会多次生成,你的应用程序实际上是否要求你强制执行?

标签: sql


【解决方案1】:

如果你选择ActivationCode作为PK,那么为什么你有两个一对一的关系?

唯一的关系是

AccountActivation.UserId -> Users.UserId

或者你认为你突然拥有什么?

如果按照您的建议去做,那么表 Users 的 PK 位于 UserId 上,而表 AccountActivation 的 PK 位于 ActivationCode 上 - 完全没有问题,也没有理由不这样做这边走。

您为AccountActivation 的PK 选择哪一列(UserIdActivationCode)并不重要——这不会影响/干扰AccountActivationUser 之间的FK 关系,也不会添加任何类型的额外一对一关系.....

如果您确实为AccountActivation 的PK 选择ActivationCode,我将采取的唯一额外步骤是在UserId 上创建一个非聚集索引,以便连接两个表的查询将受益于最大性能。

【讨论】:

    【解决方案2】:

    如果只有一个ActivationCode,他们可以共享UserId。但这意味着当用户重新生成密钥时,您应该更新旧行或删除它。

    但是为什么需要存储这些数据呢?您还可以使用来自User 的唯一数据将帐户激活码与某种计算和加密组合在一起。

    只是为了说明我的建议:

    Users table has two columns UserId CreationDate
    

    那么令牌可能是UserId + CreationDate(示例)。您将能够在数据库中没有额外数据的情况下生成和检查它。我知道这可能不符合您的要求。

    【讨论】:

      【解决方案3】:

      使 AccountActivation 中的 UserId 列成为用户表的外键。

      Users
      =====
      
      UserId primary key
      Name
      Address
      etc...
      
      AccountActivation 
      =================
      
      UserId primary key (foreign key to Users.UserId)
      ActivationCode (unique constraint)
      

      现在你有了一对一的关系

      【讨论】:

      • 或者在AccountActivation 中,primary key 可以在ActivationCode 上,并且唯一约束在UserId 上。
      • @MartinSmith - 只要 UserId 是唯一的,它将保持一对一的关系,否则,它变成一对多。
      • 那是什么反应?我没有建议不要让UserId 独一无二。如果是为了回应我对您已删除评论的回复,我指出UserId,ActivationCode 上的聚集索引将不起作用,因为您不能仅对部分键强制唯一性。
      • @MartinSmith - 你为什么要评论已删除的 cmets??
      • 什么?!我只是问你为什么在跟踪中向我提出评论 #2,因为它似乎与评论 #1 没有任何关系。我同意#2,但不确定你为什么告诉我,因为评论#1 并不矛盾......
      【解决方案4】:

      您不需要与 2 个表中的主键具有相同的列以具有一对一的关系。
      您可以将任何列作为AccountActivation 表中的主键。

      UserIdAccountActivation 表的外键,是Users 表的主键。因此,您绝对应该能够使用此列从AccountActivation 表中唯一地识别用户激活码,无论它是否是该表的主键(但它应该是唯一的,我希望它是唯一的)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-10
        • 2022-07-21
        相关资源
        最近更新 更多