可空外键错误做法?

假设您有一个包含客户 ID 的外键的表 Orders。现在,假设您想添加一个没有 Customer Id 的 Order (这是否可行是另一个问题) ,您必须将外键设置为 NULL... ... 这是不好的做法吗? 还是您更愿意使用 Orders 和 Customer 之间的链接表?虽然这个关系是1到 n,但是链接表将使它成为 n 到 n。另一方面,对于链接表,我不再使用那些 NULLS..。

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

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

编辑: 如果要链接到一个未指定的客户呢?

82542 次浏览

我看不出有什么问题,它只是一个可选的 n-1关系,在外键中用 null 表示。否则,如果你把你的链接表,然后你将不得不管理,它不成为一个 n-n 关系,所以造成更多的麻烦。

Nullable FKs for optional many-to-one relations are totally fine.

不,Nullable FK 没有什么问题。当 FK 指向的实体与主键引用表处于(0或1)到(1或多)的关系时,这种情况很常见。

例如,如果表中同时具有物理地址和邮件地址属性(列) ,并且 FK 指向地址表。当实体只有一个邮政信箱(邮政地址)时,您可以使物理地址可以为空来处理; 当邮政地址与物理地址相同(或不相同)时,邮政地址可以为空来处理。

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

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

The above would show orders older than 15 minutes without a related customer ID.

拥有链接表是 probably更好的选择。至少它没有违反正常化 BCNF(BC范式)。不过我希望你能务实一点。如果你只有很少的这些空值,而且它们只是临时的,我认为你应该跳过链接表,因为它只会增加方案的复杂性。

On a side note; using a link table doesn't necessarily make it n to n, if you in the link table use the foreign key that's pointing to your orders table as the primary key in that link table the relationship is still 1..n. There can only be one entry in that link table per order.

我曾听说过,Nullable 列通常会破坏一级规范化。但在实践中,这是非常实用的。

如果您只是在定义客户之前临时添加没有客户 ID 的订单,那么在单个事务中添加客户和订单不是更简单吗,从而消除了对 NULL 外键条目的需求,并避免了您已经设置的被违反的任何约束或触发器?

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

如上所述,对于诸如地址之类的东西,NULL 外键是可以的。但是 NULL customer 字段对订单没有意义,应该受到约束。

可选择的关系在关系模型中是绝对可能的。

您可以使用 null 来表示关系的缺失。它们很方便,但是它们会给你带来和其他地方的空值一样的麻烦。有一个地方它们不会造成任何麻烦,那就是连接。在外键中为空的行不匹配引用表中的任何行。因此,它们从内部连接中退出。如果使用外部连接,无论如何都要处理 null。

如果确实希望避免 null (第6个标准格式) ,可以分解表。两个分解的表中的一个有两个外键列。一个是您拥有的可选外键,另一个是引用原始表的主键的外键。现在您必须使用约束来防止关系变成多对多,如果您想防止这种情况发生的话。

可为空的列可以在1NF 到5NF 之间,但是根据我读到的内容,不能在6NF 之间。

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

我曾听说过,Nullable 列通常会破坏一级规范化。

参见上文,了解这个论点背后的合理原因。

But in practice it's very practical.

除非你对世界上其他地方常见的头痛免疫。其中一个令人头疼的问题(与其他 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 be”这个布尔值与实际值结合在一起。

是的,有点不对劲。如果它可以为空,那么它就不是外键。其数据库的代码设计。也许你和未分配的任务没有任何联系。如果你使用一个字符集,请保持数据的完整性100% 。

您总是可以向 Customer 表添加一个人工行,比如 Id =-1和 CustomerName = ‘ Unknown’,然后在通常将 CustomerId 设置为 Order NULL 时,将其设置为 -1。

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