【问题标题】:SQL Table Foreign Key that is part of a Composite Primary Key作为复合主键一部分的 SQL 表外键
【发布时间】:2012-09-22 15:48:19
【问题描述】:

是否可以让一个表的外键成为另一个表的复合主键的一部分? 例如,如果我有两张表,一张包含有关不同用户的所有活动项目的信息,另一张包含有关项目正在使用哪些设备的信息:

项目表:

Composite Primary Keys: UserId, ProjectId(两者都不是唯一的)

设备表:

Composite Primary Keys: UserId, ProjectId, EquipmentId(两者都不是唯一的)

现在是否可以将设备表中的 ProjectId 设置为项目表中的外键?当我尝试时,我收到一条错误消息,指出项目表中的列与现有的主键或唯一约束不匹配?

【问题讨论】:

  • 你是如何定义复合主键的?您是否在 each 列上添加了唯一约束?
  • 但我不希望每一列都是唯一的。我希望两列或三列的组合是唯一的。
  • 我问你是如何定义约束的。我没有说你应该这样定义它们。
  • 全部选中并点击设置主键。它们的列名旁边都有一个黄色键符号。

标签: sql sql-server foreign-keys primary-key


【解决方案1】:

没有。

当您创建外键时,您在另一个表中“指向”的键必须是 UNIQUE 或 PRIMARY KEY 约束。您不能建立指向允许重复值的列的外键。如果您更新另一个表中的一个重复值(例如),那么很难想象数据应该如何“起作用”。

要做你想做的事,你必须建立一个 Projects 表,其中 ProjectID 是 UNIQUE 或 PRIMARY KEY,然后将 两个 其他表中的外键指向该表。

顺便说一句,您使用术语“主键”来描述每个表中构成主键的列。实际上,每个表可以有一个且只有一个主键。该键可以由一列或多列组成,但键本身仍以单数形式引用。这是使用主键优化搜索时的一个重要区别。

【讨论】:

  • "你不能建立一个指向允许重复值的列的外键。如果你更新另一个重复值中的一个,很难想象数据应该如何“行动”表(例如)。”你能扩展一下吗?
  • 如果您有一个包含两个 Invoice #10 记录的发票抬头表,以及一个包含十一个 Invoice #10 记录的发票行表,那么第二个表中的哪一行与第一张桌子?如果您将第二个标题记录从 10 更改为 15,则明细表中的哪几行的值应更改为匹配?如果您删除抬头表中的发票 #10 记录之一,明细表中的哪些行不再有效?
【解决方案2】:

它不知道这是否是一个好的设计实践,但可以肯定的是,一个表的复合外键是另一个表的复合主键的一部分。

假设我们有一个包含复合主键 (A, B) 的表 test1

现在我们可以有一个表,说 test2 具有主键 (P, Q, R),其中 test2 的 (P,Q) 引用 test2 的 (A,B)。

我在 MySql 数据库中运行了以下脚本,它运行良好。

CREATE TABLE `test1` (
`A` INT NOT NULL,
`B` VARCHAR(2) NOT NULL,
`C` DATETIME NULL,
`D` VARCHAR(45) NULL,
PRIMARY KEY (`A`, `B`));


CREATE TABLE `test2` (
`P` INT NOT NULL,
`Q` VARCHAR(2) NOT NULL,
`R` INT NOT NULL,
`S` DATETIME NULL,
`T` VARCHAR(8) NULL,
PRIMARY KEY (`P`, `Q`, `R`),
INDEX `PQ_idx` (`P`,`Q` ASC),
CONSTRAINT `PQ`
  FOREIGN KEY (`P`, `Q`)
  REFERENCES `test1` (`A`,`B`)
  ON DELETE CASCADE
  ON UPDATE CASCADE);

在上述情况下,数据库期望 (A,B) 的组合是唯一的,并且它是 test1 表中的主键。


但是,如果您尝试执行以下操作,脚本将会失败。数据库不允许您创建 test2 表。

CREATE TABLE `test2` (
`P` INT NOT NULL,
`Q` VARCHAR(2) NULL,
`R` DATETIME NULL,
`S` VARCHAR(8) NULL,
`T` VARCHAR(45) NULL,
  INDEX `P_idx` (`P` ASC),
  INDEX `Q_idx` (`Q` ASC),
  CONSTRAINT `P`
    FOREIGN KEY (`P`)
    REFERENCES `test1` (`A`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `Q`
    FOREIGN KEY (`Q`)
    REFERENCES `test1` (`B`)
    ON DELETE CASCADE
    ON UPDATE CASCADE);

在上述情况下,数据库期望 A 列单独唯一,B 列也是如此。(A,B) 的组合是否唯一无关紧要。

【讨论】:

  • 作者想要的是逆向:test1必须有一个外键(A, B)引用(P, Q)test2。也就是说,只要在test2 中至少有一个(P, Q, R) 行与(P=A, Q=B) 相同,那么test1 中的(A, B) 行应该是有效的。这就是他想要的。
  • @izogfif 我的理解是完全正确的。不确定你的是否是。您需要了解我的回答的上下文。如果你只懂鹦鹉学舌,那不是我的问题。
【解决方案3】:

@Larry Lustig 外键可以是其他表中主键的一部分。

来源:Dependent relationship

检查表之间的关系:Zdarzenie(事件)和 TypZdarzenia(事件类型)

【讨论】:

    猜你喜欢
    • 2021-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多