【问题标题】:Foreign key reference to a two-column primary key对两列主键的外键引用
【发布时间】:2011-01-29 13:03:26
【问题描述】:

我正在构建一个必须在 MySQL、PostgreSQL 和 SQLite 上运行的数据库。我的一张表有一个两列的主键:

CREATE TABLE tournament (
    state CHAR(2) NOT NULL, 
    year INT NOT NULL,
    etc..., 
    PRIMARY KEY(state, year)
);

我想从另一个表中引用tournament 表,但我希望这个引用可为空。我可能会这样做,假设获胜者不一定有锦标赛:

CREATE TABLE winner (
    name VARCHAR NOT NULL,
    state CHAR(2) NULL,
    year INT NULL
);

如果state 为空但year 不为空,反之亦然,则该表将不一致。我相信以下FOREIGN KEY 约束可以解决它:

ALTER TABLE winner ADD CONSTRAINT FOREIGN KEY fk (name, state) REFERENCES tournament (name, state);

这是强制执行一致性的正确方法吗?此架构是否正确规范化?

【问题讨论】:

  • 为什么要让 state 和 year 可以为空?在非指定锦标赛中获胜意味着什么?
  • 实际的模式更复杂,但它是有道理的。它实际上是一个词,可能会或可能不会链接到定义表,这取决于是否知道正确的定义。

标签: sql schema primary-key


【解决方案1】:

规则 #1:始终说明您正在使用的数据库

好的,我建议您查看ON DELETE 子句和MATCH 子句。因为,Pg 相当符合 SQL 标准,所以我将向您指出 CREATE TABLE 上的当前文档。

摘录:

这些子句指定了一个外键 约束,这要求一个 一组或多列 新表只能包含值 匹配引用中的值 某行的列 参考表。如果 refcolumn 是 省略,主键 使用了 reftable。被引用的 columns 必须是 a 的列 唯一或主键约束 引用的表。注意 外键约束不能 在临时表和之间定义 永久表。

插入到引用中的值 列与 引用表的值和 使用给定的引用列 比赛类型。有三个匹配 类型:MATCH FULL、MATCH PARTIAL 和 MATCH SIMPLE,这也是 默认。 MATCH FULL 不允许一个 多列外键的列 为空,除非所有外键列 为空。 MATCH SIMPLE 允许一些 外键列为空,而 外键的其他部分不是 空值。 MATCH PARTIAL 还没有 实施。

另外,当数据在 引用的列已更改,某些 对中的数据执行操作 此表的列。删除 子句指定要执行的操作 当引用行中的 正在删除引用的表。 同样,ON UPDATE 子句 指定当一个 被引用的列中的引用 表正在更新为新值。 如果行已更新,但 引用的列实际上不是 已更改,未执行任何操作。 NO 以外的参考动作 行动检查不能被推迟,即使 如果声明了约束 可延期。有以下几种 每个子句的可能操作:

此外,MS SQL 有一个主要例外——它不允许外键中的部分匹配(MATCH SIMPLE 和 MATCH PARTIAL)行为(默认并强制 MATCH FULL)。有一些变通方法,您可以在表的任何组合键的组成部分都不是 NULL 的部分上创建 MATCH FULL 索引。

【讨论】:

  • 感谢您的全面回答。我编辑以指定我正在使用的数据库。
  • MySQL 隐含 MATCH SIMPLE 但不支持在候选键中包含 NULL(参考),请参阅:dev.mysql.com/doc/refman/5.5/en/… 了解更多信息。我不确定 sqlite,因为我很少使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 2012-06-13
  • 2015-06-30
  • 2021-09-12
  • 2020-06-04
相关资源
最近更新 更多