具有两个外键的单个表也可以被视为该表的主键(一起)吗?我添加了我正在阅读的《计算机科学邀请函第 6 版》教科书的屏幕截图,其中显示了带有两个外键的 InsurancePolicies
表,但我的问题是,这两个外键是否也被视为该表的主键桌子?教科书中作者并没有明确说明这一点。
复合键需要显式声明,即使它们由外键组成。
CREATE TABLE InsurancePolicies (
EmployeeID INTEGER,
PlanType VARCHAR(50),
DateIssue DATE,
PRIMARY KEY (EmployeeID, PlanType),
FOREIGN KEY (EmployeeID) REFERENCES Employees(ID),
FOREIGN KEY (PlanType) REFERENCES InsurancePlans(PlanType)
);
如果没有显式声明,您将不会强制执行唯一性,并且可能允许重复的(EmployeeID,PlanType)对。
KEY
是 1 个或多个具有特殊含义的列的组合。这种含义可以是索引(以加快所述列的搜索速度)、唯一的(确保表中不能存在两条记录对于作为键一部分的列具有相同的值组合)、外键(组合一起表示对另一个表的主键的引用的列)和主键,也可以是复合的。
既然您了解任何键都是 (c1, c2, ..., cn) 的形式,其中 c1 ... cn 是列,这应该澄清主键以及其他键对数量没有限制组成它的列。现在,假设您有一个 C 列,该列在它所属的表中实际上是唯一的。该字段不会成为键,不是唯一的,也不是主键,也不是任何其他字段,除非如此指定,即使它可以是唯一键或类似的主键。
唯一的列的组合是候选键,可以用作主键。
在您的
InsurancePolicies
表中
EmployeeID
是引用 Employees
的外键,并且 InsurancePlans
由名为 PlanType
的外键引用。该图没有提到它们作为(EmployeeID
和
PlanType
)的主键,并且除非深橙色意味着主键(我不相信),否则您没有理由认为它们一起是主键关键。甚至不能保证有这种可能性。如果一名员工签发了一份保险计划并支付了几个月的费用,然后切换到另一个计划,但后来又切换回他原来参与的计划,该怎么办?
假设 Employee1 于 2000 年 1 月 1 日为 InsurancePlan1 发放保险,并一直付款直至 2010 年 1 月 1 日,此时 Employee1 而不是 InsurancePlan1 为 InsurancePlan2 发放保险。然后,在 2020 年 1 月 1 日,Employee1 再次签发了 InsurancePlan1。
这意味着 Employee1 对于 InsurancePlan1 有两个不同的
DateIssued
,在当前构造中只能在
InsurancePolicies
表中的两个不同记录中表示,其 EmployeeID
和 PlanType
匹配,这就违背了使用这些记录的目的两个字段一起作为主键。如果这种情况在您的项目中由于某种原因而不可能,那么您将能够使用此组合作为主键,但即使这种情况现在不可能,随着您的项目的发展,以后也可能成为可能。
因此,正如 Boyce-Codd 在 BCNF
(Boyce-Codd 范式)中提出的那样,这是数据库规范化的进一步步骤,以避免此类复合主键,即使它们是完全合法的,因为随着时间的推移,您可能最终不得不如果大型数据库最终证明是可复制的,则重构它们。相反,此范式建议在每个表中都有一个原子的一维键,因此您将在ID
中拥有一个新的 InsurancePolicies
字段,它将成为主键,这将是一个防弹解决方案从你的外键的角度来看,因为,如果事实证明同一位员工出于某种原因可能多次拥有相同的保险计划(例如,两辆车都投保了相同的计划),那么你的模式仍然会满足目的。
关于现在(
EmployeeID
,PlanType
)是否为主键,请检查表定义,看看表定义得如何,以及这两个字段是否一起作为主键。