11

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

谢谢。

4

4 回答 4

14

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

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

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

分表实现的优点是:

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

然而,优势并非都是单向的。虽然很容易确保 aSale适用于 aVehicleSale或 aPieceSale但不能同时适用于两者,但强制执行 aSale 必须有子记录的规则实际上变得非常棘手。

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

于 2012-12-24T17:37:21.813 回答
6

回答:

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

阐述:

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

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

当 FK 是复合1并且其至少一个字段可以为 NULL 时,以特殊方式处理 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你在这里没有 - 只是为了完整性而提及它。

于 2012-12-24T17:36:41.123 回答
1

Depending on what you mean by "exclusive foreign keys", you might be thinking of vehicles and pieces as two subclasses of some larger superclass, call it saleable items.

If you use a design pattern called "class table inheritance", you will have three tables, one for the superclass, and one for each subclass table. If in addition, you use a design called "shared primary key", you can use the same primary key for all three tables.

This would enable your Sale table to have a single foreign key, Saleable_Item_Id, that references the Saleable_Item table and also either the Vehicle or the Piece table, depending on the case. This could work out better for you than the existing design.

google "class table inheritance" and "shared primary key" for more details.

于 2012-12-24T16:20:02.450 回答
0

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

您是否遇到了一些错误?

于 2012-12-24T14:53:56.427 回答