场景如下:您有一个 Persons 表,它与 Addresses 表具有一对多关系,其中 Address 行之一是“主要”地址。
在标准化模式中是否更好
- 使用 Persons.PrimaryAddressID 访问人员的“主要”地址
或者
- 使用 Addresses.IsPrimary 位列通过 Addresses.PersonID 引用人员的“主要”地址
或者
- 其他
为什么?
场景如下:您有一个 Persons 表,它与 Addresses 表具有一对多关系,其中 Address 行之一是“主要”地址。
在标准化模式中是否更好
或者
或者
为什么?
这取决于人与地址的关系是一对零加还是一对一加。
如果一个人需要有一个主要地址,我会把它放在Persons
表本身中(因为它是一个必需的属性)。
另一方面,如果一个人可以在没有地址的情况下存在于您的架构中,我会将Addresses
表中的所有地址保持相同,并使用Persons
表的属性来选择主地址(NULL 或指向相关Addresses
行的指针)。
如果您将地址的素数存储在Addresses
表中,当 Bob Smith 的两个地址都声称是主要地址时,您会怎么做?你可以用触发器来阻止它,但正确设计你的模式要高效得多。
而且,如果两个室友共享同一个地址,但一个人一直住在那里,而另一个人大部分时间都和女朋友同居,那会发生什么?如果素数在地址表中,您将无法在人员之间共享地址行。
我想要表达的是你需要将你的属性分配给正确的对象。一个人的主要地址属于一个人,而不是一个地址。
为了获得最大的效率和灵活性,我将采用以下架构:
Persons:
Id primary key
PrimaryAddressId
OtherStuff
Addresses:
Id primary key
OtherStuff
PersonAddresses:
Id primary key
PersonId foreign key on Persons(Id)
AddressId foreign key on Addresses(Id)
您有Persons.PrimaryAddressId
可能是悬挂指针的次要数据完整性问题。您不能将其作为主键之一的外键,因为您希望它允许NULL
. 这意味着您必须考虑它可能指向不存在的Addresses.Id
.
我只是将其修复为删除前触发器,Addresses
以便Persons
更新相关行(设置PrimaryAddressid
为 NULL)。
或者你可能很棘手,在Addresses
表中有一个“未知”地址,这样每一行都Persons
至少有一个地址(那些主地址未知的人会自动将其PrimaryAddressid
设置为“未知”地址行。
然后你可以使它成为一个适当的约束关系并稍微简化你的 SQL。在现实世界中,实用主义往往胜过教条主义:-)
我会选择“使用 Persons.PrimaryAddressID 来访问一个人的“主要”地址”。主要地址仅在人员链接到地址时才有意义。所以它应该属于Person。考虑以下第二种方法失败的情况。
a) Address 与另一个实体一起使用,而不引用 Addresses.IsPrimary 没有意义的人。
b) 两个人使用相同的地址,其中第一个用作主要地址,而第二个不是。
如果您希望约束是一个人至多有一个主地址,aPersons.PrimaryAddressID
显然更简单——实际上,它是由模式强制执行的。确保每个人只有一个主地址也很容易(只需使该列不为空),如果需要,甚至可以说没有两个人可以共享一个主地址(只需使该列唯一)。
当然,正是因为这种方法擅长执行这些简单的约束,所以当你不想要这些约束时,它是不好的——例如,如果你想让一个人有多个“主要”地址,则有问题的方法行不通。
顺便说一句,我不会认为一个人/多个地址的关系特别好,除非你想强制执行这样一个事实,即没有两个人可以共享同一个地址:一般来说,在正常化的情绪中,我宁愿有一个人表、地址之一和关系表(在大多数情况下,这自然是多对多的,因为许多人可以,并且在现实生活中,共享相同的地址)。
如果你选择走这条路,那么,特别是如果你需要高度的灵活性(多个主地址 &c),让关系表带有“primality”布尔值将是一个有吸引力的选择(它仍然使得执行一些上述约束,尽管其他约束,例如“地址属于至少一个人”或反之亦然,可能很难简单地表达)。
要记住的教训:准确地表达您的模式需要简单表达的约束,并且用于该目的的正确模式通常会非常清楚地出现。如果感兴趣的约束是一个谜,那么“什么是正确的模式”这个问题的答案也将是一个谜;-)。