【问题标题】:How to best implement a 1:1 relationship in a RDBMS?如何在 RDBMS 中最好地实现 1:1 关系?
【发布时间】:2009-11-13 12:44:51
【问题描述】:

昨天在做一个项目时,我遇到了一种特殊的 1:1 关系,这让我想知道 - 如何最好地实现这一点(显然,我们做错了 :D)

这个想法是有两种类型的实体,A 和 B。它们可以各自独立存在,但它们之间也可以有联系。如果有链接,那么它必须是 1:1 链接,并且双向工作。

这就像一个瓶子和一个帽子。它们可以分开存在,但是当结合在一起时,瓶子将只有一个盖子,并且盖子将只连接到一个(并且是同一个)瓶子上。

您将如何实施这种关系,同时牢记有关规范化、数据完整性等的所有最佳实践?

补充:差点忘了说 - 它们每个都有十几个属性,所以将它们放在同一个表中,其中一半字段为 NULL 是一个非常尴尬的解决方案。此外,可以随时断开链接并与另一个实体重新创建链接。

【问题讨论】:

  • 你描述的是多对多的关系。有许多可乐瓶和许多可乐盖。任何可乐盖都适合任何可乐瓶,但一个特定的可乐盖与一个特定的可乐瓶相关联。真正的一对一关系意味着我们有两个独立的实体,它们只能一起存在。如果我们有一个实体 A 的实例,我们必须有一个且只有一个匹配的实体 B 实例;此外,实体 B 的实例必须有一个且只有一个匹配的实体 A 实例。这通常是因为实体 B 是实体 A 的子类型(如实体 C、D 等)。

标签: database-design rdbms rdbms-agnostic


【解决方案1】:

为了解决这个问题,我将从标准的多对多关系布局开始。

TableA
  AId
  AInfo

TableB
  BId
  BInfo

TableA2B
  AId
  BId

然后,我将使用触发器、唯一索引、约束来强制表中的 1:1 关系。具体方法取决于系统需求。

我喜欢这种格式的原因是许多关系都有属性作为关系的一部分,而不是实体的一部分。这种模式允许现在和将来这样做。

例如:某人为一家公司工作。该关系的聘用日期不适合个人实体或公司实体。

【讨论】:

    【解决方案2】:
    CREATE TABLE A (id INT NOT NULL PRIMARY KEY, field1, …)
    
    CREATE TABLE B (id INT NOT NULL PRIMARY KEY, field1, …)
    
    CREATE TABLE AB (aid INT NOT NULL, bid INT NOT NULL,
                    CONSTRAINT pk_ab PRIMARY KEY (aid, bid),
                    CONSTRAINT ux_a UNIQUE (aid), 
                    CONSTRAINT ux_b UNIQUE (bid),
                    CONSTRAINT fk_aid_a FOREIGN KEY (aid) REFERENCES A,
                    CONSTRAINT fk_bid_b FOREIGN KEY (bid) REFERENCES B
                    )
    

    【讨论】:

      【解决方案3】:

      我认为架构应该是这样的:

      create table A (
          A_id    integer    primary key,
          ...
      );
      
      create table B (
          B_id    integer    primary key,
          A_id    integer    references A (A_id),
          ...
      );
      
      alter table B add constraint c1 unique(A_id);
      

      B只能引用A中的一行,并且由于字段是唯一的,所以A只能被B中的一行引用。

      B.A_id 可以为空,因此 A 和 B 中可以存在不相互引用的行。

      唯一约束不排除存在多个 NULL 记录。唯一约束确保所有值都是唯一的或 NULL。

      【讨论】:

      • 但是由于它是唯一的,所以不能有两行包含 NULL 的行!
      • @spoonmeiser :我的答案没有满足这个附加要求,我想我读过它,我删除了它,因为它对这个问题没有用,tx for your remakr
      • @Vilx:是的,你可以。唯一约束意味着所有值都是唯一的,但您可以有多个 NULL,因为您无法将 NULL 与 NULL 进行比较。
      【解决方案4】:

      在一端或两端具有唯一约束的可空外键取决于(两端很有趣!)

      【讨论】:

      • 是的,这就是我们现在所拥有的。两端的外键。当您尝试建立/断开链接时也很尴尬。不得不求助于触发器。我希望有一个更优雅的武器......
      • 为什么尴尬?单个事务中的两个更新应该允许您中断和/或重新配置链接。
      • 完全正确 - 一端可能更优雅,但您正在断言一端在理论上是另一端的父级,但实际上可能并非如此。
      【解决方案5】:

      将引用 A 的外键与引用 B 的外键分开连接表,两列都具有 UNIQUE 约束。因此,要么存在两个实体之间的链接并且是它们中的任何一个的唯一链接,要么不存在链接因此表中没有行。

      【讨论】:

      • 嗯。 . .@Vilx?这与您刚刚称赞的 Darryl 的解决方案相同
      • 这就是我的意思。你发布这个太慢了,其他人已经提交了完全相同的解决方案...... 20 分钟前。
      • 是的,看来达里尔的想法是一样的;我当时没有发现。不过,您不需要任何复杂的触发器来执行它,UNIQUE 外键会自行完成。
      • @Vilx:哎呀,我明白了。我以为你是在暗示 @bobince 的 solutino 太慢了。
      【解决方案6】:

      我会使用 Darryl 提出的解决方案:

      TableA
        AId
        AInfo
      
      TableB
        BId
        BInfo
      
      TableA2B
        AId
        BId
      

      然后只需在 tableA2B 中的 AId 和 tableA2B 上的 BId 上添加唯一约束

      alter TableA2B add constraint ucAId unique(AId)
      alter TableA2B add constraint ucBId unique(BId)
      

      我认为这会解决你的问题

      未链接到任何 tableB 条目的 tableA 条目将不会出现在 TableA2B 中,类似地未链接到 tableA 的 tableB 条目。

      约束将强制执行从 tableA 到 tableB 或 tableB 到 tableA 的最多一个链接

      【讨论】:

        【解决方案7】:

        IMO 有两种不同的情况需要考虑。案例一最适合描绘一夫一妻制的婚姻:这两个对象是独立创建的,并且在某个时间点将它们连接起来;稍后,它们可能会被分离,并可能与其他对象结合。对于这样的关系,我会在这里提出许多其他人使用的 A2B 表方法。

        案例二是双胞胎:如果两个物体是相连的,那么它们从出生开始就是这样,直到其中一个死亡。对于这种情况,您可以选择在创建过程中简单地为它们提供相同的主键(例如,在 Oracle 中,通过从序列中选择一个值并将其用作两个表的 ID)。

        【讨论】:

          【解决方案8】:

          “两端都有外键。尝试建立/断开链接时也很尴尬。不得不求助于触发器。我希望有一个更优雅的武器。”

          您不会在基于 SQL 的系统的世界中找到如此优雅的武器。

          Darryl Peterson 的回答显示了逻辑上正确的解决方案。但是,由于缺乏对“多重赋值”的 TTM 概念的支持,某些“更改链接”的情况可能会成为 SQL 中的噩梦。

          【讨论】:

            【解决方案9】:

            托尼·罗杰森 (Tony Rogerson) 对此发表了一篇很棒的博文: How to Create a One-to-One Relationship in SQL Server using DRI, Triggers and Views

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-09-23
              • 2011-06-04
              • 1970-01-01
              • 2011-10-05
              • 1970-01-01
              • 2020-05-08
              • 1970-01-01
              相关资源
              最近更新 更多