外键可以为空吗? [复制]

Posted

技术标签:

【中文标题】外键可以为空吗? [复制]【英文标题】:Can Foreign Key be null? [duplicate] 【发布时间】:2012-12-10 23:00:33 【问题描述】:

在我们的数据库项目中,我们有一个表 Sale,它有一个主键和两个独占外键:Vehicle_IDPiece_ID。例如,如果我们出售一辆车,我们需要 Vehicle_ID 作为外键,但不需要 Piece_ID。我们可以将 NULL 设置为 Piece_ID,外键可以为空吗?或者有没有办法完成这项工作?

谢谢。

【问题讨论】:

当然,外键可以为空。但是,您的表结构看起来有些不稳定。你想达到什么目的? 考虑审查您的设计。这种设计给您的灵活性很小。一个好的设计不会给你这种情况。在网上查找“数据库规范化” @Lion 我想在我们的自动图库项目中一次出售一辆车或一件,而不是两者兼而有之。但是,我很困惑,因为外键是另一个的主键表。我应该将销售分开为 VehicleSale 和 PieceSale 还是其他不同的东西。 【参考方案1】:

主键的一列(或多列)必须为 NOT NULL。一条记录不能由 NULL 唯一标识。所以外键引用端的 ID 列必须定义为 NOT NULL。

但是,外键关系是可选的,这是一个合理的设计决策,表示它的方式是使键的引用端是可选的,即允许 NULL。

在数据建模术语中,您所描述的是一个(排他的)弧:“一个表......具有两个或多个外键,其中一个且只有一个可以是非空的。”在逻辑建模中,弧线是完全可以接受的,但有强烈的意见支持将它们作为单独的表来实现。在您的场景中,这将是一个通用的 Sale 表加上两个子类型表 VehicleSalePieceSale

分表实现的优点是:

更容易实施外键约束; 更容易添加与(例如)不适用于计件销售的车辆销售相关的其他列; 使用额外的子类型更容易扩展模型; 更清晰的数据模型,可以简化应用程序开发。

但是,优势并非都是单向的。虽然很容易确保Sale 应用于VehicleSalePieceSale 但不能同时应用于两者,但强制执行Sale 必须 有子记录实际上得到的规则相当粗糙。

因此,普遍的建议是排他弧线是错误的,这通常是好的建议。但这并不像某些人所说的那么清楚。

【讨论】:

两表解决方案还有一个问题:如果每个销售都需要唯一标识而不管销售的“种类”(即您不能同时拥有“车辆”和“件” “使用相同的 ID 进行销售)?只是为了强制密钥的完整性,至少需要一个通用(如果不是唯一的)表,可以在其上定义此类密钥。 @BrankoDimitrijevic - 我想我已经清楚替代实现是具有子类型表的通用表,即三表解决方案。通用表将强制执行唯一性。 @APC 我可以使用触发器来控制 Piece_ID 和 Vehicle_ID 是否都为 NULL。我可以在插入一些销售时在触发器中放置一个控件。因为一次可以有一个售车、售车或两者兼有。即至少必须售出其中之一。两者都不能为NULL。 @APC 对不起,我错过了。【参考方案2】:

答案:

是的,您可以这样做 - 使 FK 本身可以为 NULL,但添加一个 CHECK 以确保其中一个包含非 NULL 值。

阐述:

FK 可以为 NULL,它模拟 1..0:N 关系。换句话说,一个“子”行可以(但不是必须)有一个“父”行。

NOT NULL 外键模拟 1:N 关系。换句话说,每个孩子必须有一个父母。

当一个 FK 是复合的1,并且它的至少一个字段是 NULL-able 时,NULL 和非 NULL 值的混合以特殊方式处理:

如果 FK 为 MATCH FULL,则 所有 值必须为 NULL,或者所有值都必须为非 NULL 并匹配某些父行。 如果 FK 是 MATCH PARTIAL,则只有那些非 NULL 值必须与某些父行匹配(忽略 NULL)。 如果 FK 是 MATCH SIMPLE,要么所有值都是非 NULL 并且必须匹配某个父行,要么至少有一个 NULL 值(在这种情况下,非 NULL 不需要匹配)。

大多数 DBMS 默认使用 MATCH SIMPLE(MS Access 除外),并且大多数 DBMS 不支持默认设置。


1 你在这里没有 - 只是为了完整性而提及它。

【讨论】:

【参考方案3】:

根据您所说的“专有外键”的含义,您可能会将车辆和零件视为某个较大超类的两个子类,称为可销售物品。

如果您使用一种称为“类表继承”的设计模式,您将拥有三个表,一个用于超类,一个用于每个子类表。此外,如果您使用一种称为“共享主键”的设计,则可以对所有三个表使用相同的主键。

这将使您的 Sale 表具有单个外键 Saleable_Item_Id,该外键引用 Saleable_Item 表以及 Vehicle 或 Piece 表,具体取决于具体情况。这可能比现有设计更适合您。

谷歌“类表继承”和“共享主键”了解更多详情。

【讨论】:

公平地说,我在问题的文本中引入了“独家”这个词,因为我认为它会澄清 OP 的要求。具体来说,销售可以适用于车辆或零件,但不是两个。【参考方案4】:

如果您有一个空外键,Oracle 不应该抱怨。

您是否遇到了一些错误?

【讨论】:

Oracle没有给我任何错误,但我无法理解逻辑:/因为外键是另一个表的主键。 空值是没有值。在您的情况下,值将是在其他地方引用主键的外键。空值表示没有值,就像它总是做的那样。在下一个抽象级别,外键表示关系。可空外键表示可选关系。没问题。

以上是关于外键可以为空吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Java varargs 可以为空吗? [复制]

两个外键引用一个表和可以为空的外键

sql 关联查询外键为空的情况

mysql外键

在集合形式外键始终为空

HIbernate 无法删除具有外键的实体。外键设置为空