1

给定架构

人{姓名,配偶}

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

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

我有一个备用架构

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

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

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

4

7 回答 7

2

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

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

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

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

......所以只有女性的人才能有一个非空的配偶。

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

于 2008-12-15T15:56:03.707 回答
1

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

于 2008-12-15T15:42:02.080 回答
1

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

我将暂时忽略将名称用作主键(它可以更改并且重复相当普遍,因此这是一个糟糕的选择),并且我还将忽略对历史跟踪的可能需求(您可能想要添加某种生效日期,以便您知道他们何时是配偶 - 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

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

于 2008-12-15T17:12:37.357 回答
0

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

于 2008-12-15T15:52:05.820 回答
0

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

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

存储过程(无论是否触发)比应用程序级完整性代码更可取,但它们实际上不如声明性支持且风险更大,因为它们编写起来更加繁琐、容易出错,并且无法从完整的 DBMS 优化中受益。

...

选择具有更好的声明完整性支持的 DBMS。鉴于产品在此类支持方面存在相当大的差距,知识渊博的用户至少能够 正确模拟(尽管使用过程和/或应用程序代码)不受 DBMS 支持的约束。

于 2008-12-15T15:52:17.097 回答
0

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

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

于 2008-12-15T16:00:31.637 回答
0

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

人(身份证、姓名等);

Partner_Off (id, partner_id, 关系);

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

于 2008-12-15T16:46:18.970 回答