1:1或1:0关系的归一化

时间:2011-03-03 07:48:42

标签: database relational-database normalization 3nf

当使用关系数据库并且你想要3NF时(你用英语称它为3NF吗?),那么你将1:1关系一起拉到一个表中。但如果合理性是1:0/1(/意思或),会发生什么?

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

3 个答案:

答案 0 :(得分:3)

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

如果你有一个属性,那么该属性本身可能仍然遵循规则。

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

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

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

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

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

答案 1 :(得分:3)

根据您对@ paxdialbo答案的问题和后续评论,我的理解是您需要一个存储可选属性的解决方案,其中有很多,同时避免使用NULL。完成此操作的两种方法,6th Normal Form(6NF)或Entity Attribute Value(EAV)模型。

第6范式

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

create table attributeName (
    id
    value
)

其中id是外键,value捕获该属性(例如社会安全号码)。没有给定密钥的记录表明不存在。

实体属性值

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

create table integerAttribute (
    name
    id
    value
)

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

结论

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

答案 2 :(得分: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。)

你说

  

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

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

  • 人类“有一个”[birth_date]
  • 人类完全出生 [birth_date]

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

你说

  

但现在你神经过敏了   但只有人类的孩子

我不确定你的意思是“纯粹的人类”。你可以通过简单地获得所有人类

SELECT * FROM human;

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