可空的外键坏习惯?

时间:2009-11-12 17:07:40

标签: database-design

假设您有一个表订单,其中包含客户ID的外键。现在,假设你想添加一个没有客户ID的订单,(这是否可能是另一个问题)你必须使外键为NULL ...这是不好的做法还是你宁愿使用链接表订单和客户?虽然关系是1到n,但是链接表会使n到n。另一方面,使用链接表,我不再拥有那些NULLS ......

数据库中实际上不会有很多NULL,因为具有NULL的外键的记录只是临时的,直到添加了订单的客户。

(在我的情况下,它不是订单和客户)。

编辑:未指定的客户链接到哪个?

11 个答案:

答案 0 :(得分:103)

否Nullable FK没有任何问题。当FK指向的实体与主键引用表处于(零或一)到(1或多)关系时,这很常见。

示例可能是如果表中同时具有物理地址和邮件地址属性(列),并且FK为地址表。当实体只有邮局信箱(邮寄地址)时,您可以使物理地址可以处理,邮件地址可以自由处理邮寄地址与物理地址相同(或不是)。

答案 1 :(得分:45)

让链接表可能是一个更好的选择。至少它不违反标准化BCNF(博伊斯 - 科德正规形式)。但我赞成务实。如果你只有很少的这些空值而且它们只是暂时的,我认为你应该跳过链接表,因为它只会增加方案的复杂性。

旁注;如果你在链接表中使用指向你的订单表的外键作为该链接表中的主键,那么使用链接表并不一定会使它成为n到n,关系仍然是1..n。每个订单的链接表中只能有一个条目。

答案 2 :(得分:35)

  

根据我所读到的内容,可以为Nullable的列可以是1NF到5NF,但不是6NF。

只有你比Chris Date更了解“第一个正常形式的真正含义”。如果x和y都可以为空,并且在某些行x和y都是null,那么WHERE x=y不会产生true。这无可置疑地证明null不是一个值(因为任何实际值总是等于它自己)。由于RM规定“表格的每个单元格中都必须有值”,任何可能包含空值的东西都不是关系型的东西,因此甚至不会出现1NF的问题。

  

我听说它认为Nullable列通常会破坏第一级标准化。

请参阅上文,了解该论据背后的合理原因。

  

但在实践中它非常实用。

只有当你对世界其他地方通常会引起的头痛免疫时,才能免疫。一个这样的头痛(并且只是一个小问题,相对于其他null现象)是SQL WHERE x=y实际上意味着WHERE x is not null and y is not null and x=y,但大多数程序员根本不知道那个事实,只是阅读它。有时没有任何伤害,有时则没有。

实际上,可空列违反了最基本的数据库设计规则之一:不要在一列中组合不同的信息元素。 Null正是这样做的,因为它们将布尔值“this field is / is not really present”与实际值组合在一起。

答案 3 :(得分:13)

我看不出有任何错误,它只是一个可选的n-1关系,将在外键中用null表示。否则,如果您放置链接表,那么您将必须管理它不会成为n-n关系,因此会造成更多麻烦。

答案 4 :(得分:3)

关系模型中绝对可以使用可选关系。

您可以使用空值来表示没有关系。它们很方便,但是它们会让你产生与其他地方无效的头痛。他们不会造成任何麻烦的地方是加入。外键中具有null的行与引用表中的任何行都不匹配。所以他们退出了内部联盟。如果你做外连接,你将会处理空值。

如果你真的想避免空值(第6种普通形式),你可以分解表格。两个分解表中的一个具有两个外键列。一个是您拥有的可选外键,另一个是引用原始表的主键的外键。现在你必须使用约束来防止关系变成多对多关系,你要防止这种关系。

答案 5 :(得分:2)

使用NULL将是清理不完整订单的好方法:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

以上将显示超过15分钟且没有相关客户ID的订单。

答案 6 :(得分:0)

可选的多对一关系的Nullable FK完全没问题。

答案 7 :(得分:0)

如果您只是在定义客户之前暂时添加没有客户ID的订单,那么在单个事务中添加客户和订单会不会更简单,从而无需使用NULL外键输入并避免任何你设置的约束或触发器是否被违反?

通常情况下,在客户定义他/她之前订单详细的网络应用程序中会出现这种情况。在这些情况下,订单将保持在服务器状态或cookie中,直到提供完整订单的所有必要状态,此时订单将持久保存到数据库。

如上所述,NULL外键适用于地址之类的东西。但是NULL客户字段对订单没有意义,应该受到限制。

答案 8 :(得分:0)

您总是可以在Customer表中添加一个人工行,例如Id = -1和CustomerName ='Unknown',然后在通常将OrderId设置为Order NULL的情况下将其设置为-1。

这允许您没有可空的FK,但仍然表示缺少适当的数据(并且将使您免于下游用户不知道如何处理NULL)。

答案 9 :(得分:-1)

我听说它认为Nullable列通常会打破第一级标准化。但在实践中它非常实用。

答案 10 :(得分:-1)

是的,这是错的。如果它可以为空,它不是外键。它的数据库按代码设计。也许你建立一个未分配的零链接。如果您使用字符col,则为“Unassigned”。保持数据的完整性100%。