我有一个具有以下结构的三级数据库(简化为仅显示主键):
Table A: a_id
Table B: a_id, b_id
Table C: a_id, b_id, c_id
因此表C的可能值是这样的:
a_id b_id c_id
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
2 1 1
2 2 1
2 2 2
...
我现在不确定,应该如何设置外键;或者是否应该为主键设置它们。我的想法是在表B B.a_id -> A.a_id
上有一个外键,在C C.a_id -> A.a_id
和( C.a_id, C.b_id ) -> ( B.a_id, B.b_id )
上有两个外键。
这是我设置外键的方式吗?来自C->A
的外键是否必要?或者我甚至需要外键,因为所有这些列都是主键的一部分?
感谢。
答案 0 :(得分:3)
首先,必须使用外键来断言父表中是否存在记录,而主键则使用表来声明记录的唯一性。所以你需要两者。
一般来说,您希望避免使用复合主键。所以你的表应该是这样的:
表A:a_id(pk)
表B:b_id(pk),a_id(fk)
表C:c_id(pk),b_id(fk)
表C和表A之间不需要外键,因为表C和表B以及表B和表A之间的外键暗示了这种关系。
修改强>
使用化合物有什么不好 主键?
将表C连接到表B时,只需要少一行。当我们传播外键时,列数会累积,因此表D将具有四列的复合主键。在某些时候,这开始感到愚蠢。我曾经在一个系统上工作,该系统的表J带有 9个主键列和两个数据列。
另一方面,复合键也可以与业务键相关联。将那些作为外键传播可能是一个真正的痛苦。一旦我们决定为一个表使用代理(合成)密钥 - 自动增量,序列,guid,等等 - 一致性表明我们应该对所有表使用相同的主键机制。
有一些ORM工具使得复合键难以使用。我不认为这是不使用复合键的一个很好的理由,因为我强烈反对驱动我的数据模型的ORM工具的局限性,我只是指出它。
另一方面,使用复合键可能是有利的。我在一个系统上工作,我们不得不对格式进行大量查询
select D.*
from D
join A on ( D.a_id = A.id )
where A.some_col = 'whatever'
不必将表D连接到表C到表B以获得表A是一个明确的福音。当用户可以访问表A中托管子集的基础上,他必须限制对所有表的访问时,这甚至可以更真实地实现虚拟专用数据库。
所以这不是一个硬性规定。在争论的两个方面,人们都对这一点感到强烈。在我的职业生涯中,我强烈支持复合主键,但现在我发现自己通常会支持单列主键,并在适当的时候使用复合业务键强制执行。
简而言之,复合主键不是错误只是笨重。单列,代理主键可能是行业标准。但是,有些情况下复合主键是正确的选择。
答案 1 :(得分:1)
如果表B和表A之间已经有一个外键,以确保表B只包含表A中存在a_id
值的条目,那么表C和表A之间的额外FK a_id
上没有必要。当然,这要求表B和表A之间的FK关系被加密,激活,而不是以任何方式禁用或规避。
在表C和表B之间建立FK链接已经保证TableC.a_id
只能引用有效值a_id
(因为表B中通过表B和表之间的FK关系保证了这一点) A)。