【问题标题】:What is the best way to represent a 1:1 relationship in a database在数据库中表示 1:1 关系的最佳方式是什么
【发布时间】:2014-10-11 14:42:37
【问题描述】:

您认为哪种方式是定义一对一关系(例如配偶)的最佳方式?

在我的实际数据库中,我有一张人员表,其中有些人将与表中的其他人归类为“联合”(因此该人将与原始人联合)。 “联合”将用于确定每个人的付款。

我可以有类似的东西

PERSON
------
Person_ID   (PK)
Name
Phone
Joint_With_ID  (FK)

Joint_With_ID 可以为 null 或包含与他们联合的记录的 Person_ID(并且该人的记录包含第一人的 person_ID),但我不喜欢故意为空。

或者我可以有两张桌子

PERSON                    PERSON_JOIN
------                    -----------
Person_ID   (PK)          Joined_ID       (PK)  
Name                      Person_ID
Phone                     Joined_With_Person_ID 

并在 PERSON_JOIN 中为每对联合的夫妇提供两条记录 即

Person_ID   Joined_With_Person_ID
   5              8
   8              5

这两种情况都增加了 person1 被记录为与 person2 联合但不存在 person2 与 person1 联合的记录的可能性。

我什至可以在 PERSON_JOIN 中为每次加入只有一条记录,并在尝试查看一个人是否联合以及与谁在一起时使用 SQL 搜索这两个字段。但这太可怕了!

那么……最好的方法是什么?

【问题讨论】:

  • "并且在 PERSON_JOIN 中为每一对联合的夫妇有两条记录" 那么元组 {5, 8} 和 {8, 5} 之间的信息没有区别吗?我问是因为您在谈论付款,而在某些应用程序中,这两个元组意味着两个不同的东西。
  • 是的,我更喜欢这种方法,但你说的是正确的,我也很担心——因此我提出了问题。该应用程序需要知道一个人是否与其他人一起决定他们是否支付联合费用或个人费用。如果他们是联合的,那么加入的双方将支付联合费用。但是,正如您所说,如果用于查看某人是否加入的 sql 可以同时考虑这两个字段,则其中一个元组是多余的。我更愿意以某种方式将其构建到架构中。
  • 我没有说其中一个元组是多余的。我说过,在某些应用程序中,这两个元组意味着不同的东西。
  • 对不起,迈克,我知道你没有这么说。我想我有点怀疑在这种特殊情况下一个是否是多余的,因为 sql“可以”对其进行排序,或者双记录是否是更好的方法,尽管它们都提供了相同的信息

标签: database relational-database entity-relationship


【解决方案1】:

在我的实际数据库中,我有一张人员表,有些人会 与表中的其他人被归类为“联合”(并且 因此,人将与原始人联合)。这 “联合”将用于确定每个人的 [原文如此] 付款。

在 SQL 数据库中执行此操作的常用方法是对 id 号施加顺序,并通过检查约束来保证顺序。这假设元组 {5, 8} 与元组 {8, 5} 的含义相同,并且假设一个人不能加入她自己。这里要小心。

如果我有“8 与 5 结婚,5 与 8 结婚”,我会认为这些意思相同。但“8 是 5 的从属”并不意味着“5 是 8 的从属”。

create table person_join (
  person_id integer not null references person (person_id),
  joined_with_person_id integer not null references person (person_id),
  primary key (person_id),
  check (person_id < joined_with_person_id)
);

如果需要加入多人,将主键约束改为

  primary key (person_id, joined_with_person_id),

您可能需要一个额外的索引,因为您或多或少需要独立查询两列。

create index on person_join (joined_with_person_id);

如果你想知道“5”是否有加入的人,你可以

select *
from person_join
where person_id = 5 
   or joined_with_person_id = 5;

【讨论】:

  • 这似乎是最好的折衷方案,person 表中没有空值,连接表中只需要一条记录。用户界面将阻止自我加入,因为用户在创建联合记录时只能从所有“其他”人中选择某人。
【解决方案2】:

配偶关系通常不是 1:1 — 不是每个人都有配偶。它更像是“0 或 1”到“0 或 1”,忽略一夫多妻制和一夫多妻制的社会。有些人但不是所有人都有配偶,而那些有配偶的人一次最多只有一个配偶。 (记录谁是谁的配偶的历史是另一个单独的bag'o'worms。)

因此,您的 PERSON_JOIN 架构设计是两者中的佼佼者。

【讨论】:

  • 是的,这也是我的想法。在这种情况下,不是真正的配偶,这个人要么有共同的人,要么没有共同的人。如果他们这样做了,那么那个人也有一个共同的人(另一个人)。我担心的是,SQL 负责确保每次插入插入两条记录,每次删除删除两条记录,每次更新至少更新 2 条但可能最多更新 4 条记录(如果 personA 不再与 personB 联合但与 personC 联合- 因此,personC 已与 personB 联合(并且可能不再与 personD 联合)。这是 SQL 的一个脆弱点!
  • 如果您一次完成所有操作,那么它不必停留在 4 条记录上:如果您在进行任何更改之前有 A=B、C=D、E=F、G=H,之后,A=C,B=E,D=G,你还有新的任务要让 F 和 H 操心。为了简化,您需要分两步进行重新分配;所有受影响方的取消分配步骤(之前给定 A=B 和 C=D,之后给定 A=C,然后取消分配 A、B、C 和 D,然后分配 A 和 C)。这限制了伤害。你确定这种关系总是互惠的吗?对于配偶来说,它是;对于社交网站上的朋友来说,事实并非如此。了解您的数据至关重要。
  • 倒数,是的。商业规则说,如果两个人(并且只有两个人)是“合作伙伴”并且住在同一个地址,那么他们就是联合的​​。此应用程序的用户将决定他们是否是联合的,并将创建“加入”记录,可能是在将第二个人插入到人员表中时,也可能是稍后,当“加入”被定义为已经发生时。 (我打算编辑我​​的评论以考虑到您突出显示的事件链,但网站不允许这样做。我将不得不考虑实施您建议的 sql,因为 person 表中的每个人都可以交换! )
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-10
  • 2012-07-09
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
相关资源
最近更新 更多