【问题标题】:Factoring out nulls in bill-of-materials style relations排除物料清单样式关系中的空值
【发布时间】:2008-12-15 15:36:13
【问题描述】:

给定架构

人{姓名,配偶}

其中 PERSON.spouse 是 PERSON.name 的外键,当一个人未婚或我们没有任何信息时,NULL 是必需的。

继续反对空值的论点,在这种情况下你如何避免它们?

我有一个备用架构

人{姓名} 配偶{姓名1,姓名2}

其中 SPOUSE.name* 是 PERSON 的 FK。我在这里看到的问题是,没有办法确保某人只有一个配偶(即使有所有可能的 UNIQUE 限制,也有可能有两个配偶)。

在物料清单样式关系中排除空值的最佳方法是什么?

【问题讨论】:

    标签: sql database referential-integrity


    【解决方案1】:

    我认为对这种类型的关系不强制执行 NULL 和不重复会使模式定义变得比实际需要的复杂。即使您允许空值,一个人仍然有可能拥有多个配偶,或者有冲突的记录,例如:

    PERSON { A, B }
    PERSON { B, C }
    PERSON { C, NULL }
    

    您需要引入更多数据,例如性别(或同性婚姻的“配偶编号”?),以确保例如只允许一种类型的人拥有配偶。另一方的配偶将由第一方的记录确定。例如:

    PERSON { A, FEMALE, B }
    PERSON { B, MALE, NULL }
    PERSON { C, FEMALE, NULL }
    

    ... 这样只有女性的 PERSON 才能拥有非空配偶。

    但是恕我直言,即使使用 NULL,这也过于复杂且不直观。如果没有 NULL,情况会更糟。除非你真的别无选择,否则我会避免进行这样的架构限制。

    【讨论】:

    • 我并没有真正考虑到使用空值可能带来的所有问题。我希望我能不止一次投票给你。
    【解决方案2】:

    嗯,首先我会使用自动递增的 ID,因为当然,有人可能有相同的名字。但是,我假设您打算这样做并且不会竖琴。然而,反对 NULL 的论点究竟如何呢?我对 NULL 没有任何问题,并认为这是解决此问题的适当方法。

    【讨论】:

    • 一些关系理论家,尤其是 Chris Date,非常反对 NULL,因为 NULL 可能意味着未知或不存在。此外,三值逻辑很烂。
    • 我已经阅读了一些反空参数;我想我只是对他们不满意,这导致我们遇到这种问题。我认为解决存在 NULL 的问题在大多数情况下并不是很困难。
    • 遇到了 NULL 问题,我愿意与理论家一起去,但我不确定我上面的解决方案如何比保持原样更好,就像你一样我推荐了。
    【解决方案3】:

    我不确定为什么还没有人指出这一点,但实际上很容易确保一个人只有一个配偶,使用与您的问题几乎相同的模型。

    我将暂时忽略将名称用作主键(它可以更改并且重复相当普遍,因此这是一个糟糕的选择),并且我还将忽略可能需要历史跟踪(您可能想添加某种生效日期,以便知道他们何时是配偶 - Joe Celko 写了一些关于时间建模的好东西,但我不记得当时它在哪本书中) .否则,如果我离婚再婚,你就会失去我在另一个时间有另一个配偶的感觉——也许这对你来说并不重要。

    此外,您可能希望将 name 分解为 first_name、middle_name、last_name、prefix、suffix 等。

    鉴于这些警告......

    CREATE TABLE People
    (
         person_name     VARCHAR(100),
         CONSTRAINT PK_People PRIMARY KEY (person_name)
    )
    GO
    CREATE TABLE Spouses
    (
         person_name     VARCHAR(100),
         spouse_name     VARCHAR(100),
         CONSTRAINT PK_Spouses PRIMARY KEY (person_name),
         CONSTRAINT FK_Spouses_People FOREIGN KEY (person_name) REFERENCES People (person_name)
    )
    GO
    

    如果您想让配偶也出现在“人员”表中,那么您也可以为此添加 FK。但是,此时您正在处理双向链接,这变得有点复杂。

    【讨论】:

    • 暗示配偶将处于 PERSON 关系中。如果我们使用您提到的双向链接,它与问题中的备用模式有何不同?
    【解决方案4】:

    好的,使用自动 ID,然后使用检查约束。 “Name1”列(这将只是一个 int ID)将被强制只有奇数编号的 ID,而 Name2 将只有偶数。

    然后为 Column1 和 Column2 创建一个唯一约束。

    【讨论】:

    • 这很漂亮。我需要花几分钟来说服自己它有效。
    • 该设计的插入语句是什么样的?
    • 插入语句将是一个普通的旧插入语句。但是,您必须在发出语句之前执行一些逻辑来确定应该将其插入哪个字段。
    • 从关系建模的角度来看,我认为这不是一个好的答案。您正在添加一个综合属性来解决 SQL 中缺乏声明性约束的问题。
    • 我同意这有点“hackish”,但看看 Adam Bellaire 指出的使用 NULL 的问题。
    【解决方案5】:

    好吧,从使用 name 以外的键开始,也许是 int 种子。但是为了防止某人拥有多个配偶,只需在配偶表中的 parent(name1) 中添加一个唯一索引。这将阻止您两次插入相同的 name1。

    【讨论】:

    • 但是name1列和name2列可以显示相同的名字。
    【解决方案6】:

    您需要一个人表和一个单独的“Partner_Off”表来定义关系。

    人物(身份证、姓名等);

    Partner_Off(id、partner_id、关系);

    要处理更复杂的社交情况,您可能需要在其中添加一些日期,此外,为了简化 sql,您需要一个 (fred,wilma,husband) 条目和一个匹配条目 (wilma,fred,wife) )。

    【讨论】:

    • 这似乎与问题中的备用模式相同。有什么不同?
    【解决方案7】:

    您可以使用触发器来强制执行约束。 PostgreSQL 有constraint triggers,这是一种将约束评估推迟到事务中的适当时间的特别好的方法。

    来自 Fabian Pascal 的数据库管理中的实际问题,第 66-67 页:

    存储过程——无论是触发还是 不——比应用更可取 级完整性代码,但它们是 实际上不如和风险更大 而不是声明性支持,因为它们 写起来比较麻烦,错误 容易,并且不能充分受益 DBMS 优化。

    ...

    选择具有更好声明性的 DBMS 诚信支持。鉴于 在这种支持方面存在相当大的差距 产品,知识渊博的用户将 至少可以效仿 正确——尽管有程序和/或应用程序代码——约束 DBMS 不支持。

    【讨论】:

    • 这是我的第一个想法,但我认为性能可能会成为非常大的 BOM 关系实例的问题。
    • 无论约束如何拼写,性能问题都是相同的。如果您的 DBMS 在声明性检查约束内支持子查询,则会产生相同的成本。
    • 如果必须引入很多触发器来避免使用NULL,这有点令人担忧。
    • 你不需要引入触发器来避免 NULLS。当 SQL 中的声明性约束不够表达时,需要引入触发器。
    • 我没有读过 Pascal 的任何作品。你如何看待他 vs Date vs Celko?
    猜你喜欢
    • 2012-03-29
    • 2010-10-12
    • 2014-04-14
    • 2013-08-27
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 2013-09-30
    • 1970-01-01
    相关资源
    最近更新 更多