3

当使用关系数据库并且你想要 3NF 时(你用英语称之为 3NF 吗?),然后你将 1:1 的关系拉到一个表中。但是如果配给比例是 1:0/1(/ 意思是或)会发生什么?

然后你把它们分开以避免表格中的空格?在这种情况下,将它们分开是有效的 3NF 吗?

4

3 回答 3

3

根据您的问题和随后对@paxdialbo 的回答的评论,我的理解是您想要一个存储可选属性的解决方案,其中有很多,同时避免空值。实现这一点的两种方法,第 6 范式(6NF) 或实体属性值(EAV) 模型。

第六范式

这涉及创建特定于属性的表:

create table attributeName (
    id
    value
)

外键在哪里idvalue捕获该属性(例如社会安全号码)。给定键的记录不存在表示不存在。

实体属性值

现在您可以想象,第 6 范式可以导致表格扩散。EAV 模型通过对多个属性使用类似模型来解决,例如:

create table integerAttribute (
    name
    id
    value
)

name标识属性(例如“SocialSecurity”),尽管更复杂的实现不是name列,但name存储在单独的元数据表中并通过外键引用。无论如何,这种方法意味着有其他表用于不同的数据类型(即datetimeAttributevarcharAttribute等...)。

结论

要考虑的真正问题是您正在处理多少可选属性。如果相对较少,最简单的解决方案实际上是在主表上添加可选的 NULLable 列。6NF 和 EAV 增加了显着的复杂性和性能问题。使用其中一种方法时,通常所做的是将整个实体序列化为主表上的 CLOB 以简化常见读取(即通过主键),以避免多个 LEFT 连接来检索完全水合的实体。

于 2011-03-03T11:57:52.367 回答
3

第三范式基本上意味着一个属性(或列)取决于键,整个键,只有键(所以帮助我,Codd)。

如果您有一个存在或不存在的属性,则该属性本身可能仍遵循规则。

在这些情况下,我只需将属性保留在主表中,并使它们可以为空,以指示它们是否适合该行。

通过(人为的)示例,您可能有一个SocialSecurityNumber属性作为您的主键(我不会讨论这是否是一个好主意,或者您是否应该使用代理键,因为它与问题无关) .

进一步假设您有一个独特的BankAccount属性来支付他们的工资,并且您不是那些可以将工资分配到多个银行账户以避税的好雇主之一:-)

现在某人的银行账户完全依赖于所选择的密钥,但不是每个人都可以拥有一个(他们可能以现金支付)。换句话说,1:0/1正如您所说的那样,这是一个经典案例。

在这种情况下,您只需将表中的银行帐号设为可空即可。

于 2011-03-03T08:29:31.333 回答
2

基于您对 paxdiablo 的评论。. .

让我们看一些 SQL。我本可以为这些列选择更好的名称,但我故意没有。我不是懒惰;我有充分的理由。外部谓词是用户应该如何解释表的内容。

-- External predicate: Human is identified by 
--                         Social Security Account Number [ssan] 
--                     and has full name [full_name] 
--                     and result of last HIV test [hiv_status]
--                     and has checking account [bank_account]
--                     and was born at exactly [birth_date].
--
create table human (
ssan char(9) primary key, 
full_name varchar(35) not null,
hiv_status char(3) not null default 'Unk' 
    CHECK (hiv_status in ('Unk', 'Pos', 'Neg')),
bank_account varchar(20),
birth_date timestamp not null
);

-- External predicate: Human athlete identified by 
--                         Social Security Account Number [ssan] 
--                     has current doping status [doping_status]
create table athlete (
ssan char(9) not null primary key references human (ssan),
doping_status char(3) not null default 'Unk' 
    CHECK (doping_status in ('Unk', 'Pos', 'Neg'))
);

-- External predicate: Human dictator identified by 
--                         Social Security Account Number [ssan] 
--                     has estimated benevolence of [benevolence_score].
create table dictator (
ssan char(9) not null primary key references human (ssan),
benevolence_score integer not null default 3 
    CHECK (benevolence_score between 1 and 5) -- 1 is least, 5 is most benevolent
);

所有这三个表都在 5NF 中。(这意味着他们也在 3NF 中。)

你说

关系数据库中没有“IS A”关系

运动员“IS A”人类,因为它的标识符是人类标识符。在这种情况下,它的主键是一个外键references human (ssan)。数据库设计者通常不会谈论“IS A”和“HAS A”关系,因为谓词更加精确和富有表现力。通过比较这两个语句,您可以看到差异。

  • 人类“有一个”[birth_date]
  • 人类恰好在 [birth_date] 出生

最后一个故意有点刺耳。我将birth_date 列定义为时间戳——它同时包含日期和时间。它说明了外部谓词如何在某种程度上独立于列名。(它还说明了谓词和列名之间的松散耦合在这里可能不是一个好主意。)

你说

但是现在你更胆小得到一个纯人类但只有人类的孩子

我不确定你所说的“纯人类”是什么意思。你可以简单地得到所有的人

SELECT * FROM human;

如果您的意思是除非人类是运动员或独裁者(或其他任何人),否则您不能拥有人类,那么您就错了。如果运动员中没有特定 SSAN 的行,则由该 SSAN 识别的人不是运动员。如果特定 SSAN 的独裁者中没有行,则由该 SSAN 识别的人不是独裁者。

于 2011-03-05T16:15:24.037 回答