【问题标题】:SQL database designSQL数据库设计
【发布时间】:2010-03-02 10:47:52
【问题描述】:

我正在为一个程序创建一个数据库,我应该在其中模拟家庭中的一些关系。 例如: X 是 Y 的父亲,Y 是 X 的儿子

所以,我有一个 Members 表,其中包含有关每个成员的所有信息,所以我考虑在 Members 表与其自身之间建立多对多关系,以便 Member_Member 桥表将列 "FK_FromID , FK_ToID" 作为复合键(正确吗?)和 "FK_RelationType" 作为外键到 RelationTypes 表,该表将具有关系类型 "Father,mother,son,daughter" ,并且从 Members 表到这两个外键的两个关系是一对多的

我的问题是:删除时如果我选择级联,那么我会产生循环,因为如果我删除一个成员,那么 Member_Member 中的相关记录会有两次删除传递桥,知道在程序中每当我插入父亲关系时,我都会在 Member_Member 表中插入儿子关系,有没有办法或解决方法可以启用级联,以便每当我删除成员时,我都会删除相关记录在 Member_member 中,无论记录在 to 或 from 外键列中

所以,我不知道该怎么办,这是一个正确的设计还是什么? ,我应该怎么做自行车,还有你认为对于同样的问题更好的设计应该是知道我需要指定两方之间什么样的关系

非常感谢您的帮助,抱歉英语不好 小鱼

【问题讨论】:

    标签: sql database-design family-tree


    【解决方案1】:

    SQL 不能很好地处理这样的“网络”问题。

    成员-成员桥接表是一个可怕的名字。这是一个“成员-父母”(或“父母-孩子”)的桥梁。桥接表不应有“复合键”。桥接表有一个代理键(只是一个序号)和一对对其他表的 FK 引用。这两个 FK 应该具有像“member”和“parent”这样的名称,以便完全清楚地说明此表中的关系。

    每个人都有父母。不是每个人都有孩子。有些父母在这个数据库中没有父母;他们是“顶级父母”。

    如果顶级父级在父子桥中具有父 FK 为 NULL 的行,这是最简单的。这样你就可以避免超复杂的外连接——每个成员至少有一个成员父行;最好是两个。

    您会发现许多“循环”问题,因为关系是可传递的。

    请注意,您无法在单个标准 SQL 查询中找到所有家庭成员,或所有回到家庭顶部的父母,或所有子孙。有一些 SQL 扩展使这成为可能,但标准并不能很好地处理它。

    级联删除效果不佳,因为家庭中的关系有两种方向(父对子,子对父),但 SQL 只有一种方向(FK 引用)。

    您可以尝试确保每个成员必须在“member-parent”中至少有一个(最多两个)行并且删除一个成员会删除“member-”中的两行父”并且键有正确的名称,你可以做这个工作的一部分。

    请注意,当您删除成员时,这会破坏他们的父关系。您删除了成员父行。那挺好的。他们的孩子呢?其他具有成员父级引用此已删除父级的行现在已损坏。这是什么意思?应该做什么?

    没有标准答案。从连通图中删除行会留下元素 未连接。你必须为此制定一些合理的规则。

    由于 SQL 在这方面做得不好,所有的设计似乎都会有问题。

    【讨论】:

    • +1 因为我同意大部分内容。我不同意桥表不应该有“复合键”。只有当桥表有自己的属性或在外键中引用时,代理主键才是必需的。即使这样,复合键也应该作为唯一键强制执行。
    • @APC:如果您要使用 ORM,您将需要代理键。一旦你采取了这一步,复合键就是一个不必要的复杂性。只需为性能创建一个索引并完成它。
    • 代理键不强制关系完整性。它们是有用的设备,但我们仍然应该强制执行 业务键,无论是单列还是多列。现在很多人都对应用程序强制数据完整性的想法感到满意,但我不是其中之一。除了提问者问的是数据库设计而不是 ORM,所以我认为我的观察仍然有效。
    • @APC:代理键不强制完整性?真的吗?为什么不?什么是“业务密钥”?一条数据可能因为拼写错误而发生变化,进而引发一连串的变化?
    • 我不禁觉得这超出了 cmets 线程的范围。反正。代理键是无意义的标识符;业务密钥是现实世界中唯一事物的标识符。但是您是对的,业务密钥可以更改,这就是代理密钥有用的原因。铸铁示例:电子邮件地址是唯一的,但用户会希望更改与其帐户关联的地址。因此,为了避免这种级联(和其他复杂情况),我们有一个代理用户 ID(数字)。但是我们仍然希望在 Accounts 表中强制执行电子邮件的唯一性。我们不是吗???
    【解决方案2】:
    1. 假设每个成员只能有一个母亲和一个父亲,您只需在 members 表中保留一个 mother_idfather_id 字段即可推导出所有关系。

      但是,这只有在您的数据库不会缺少信息的情况下才有效。例如,如果成员 X 是成员 Y 的兄弟,则除非 X 和 Y 的父母都存储在数据库中,否则无法知道这一点。

      如果您的数据库不会丢失信息,上述方法可能更容易管理数据完整性。然而,查询可能会变得有点复杂。

    2. 你建议的member_member桥有一个严重的问题,因为它暗示了关系的方向,所以如果X是Y的父亲,Y也是X的儿子。你建议定义关系两个方向两次,但一般不建议这样做。这是数据复制的一种形式,您可能很难通过数据复制来强制执行参照完整性。请记住,DBMS 不知道 X 是 Y 的父亲与 Y 是 X 的儿子是一样的。

    我知道这不是一个完整的答案,而只是一些观察。我完全同意S.Lott's answer,因为没有标准的方法可以用关系数据库“解决”这个问题。

    【讨论】:

    • 非常感谢您的回答,非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 2019-11-27
    • 2015-05-17
    • 2011-09-22
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多