代码之家  ›  专栏  ›  技术社区  ›  poke

三级数据库-外键

  •  1
  • poke  · 技术社区  · 14 年前

    我有一个三级数据库,其结构如下(简化为仅显示主键):

    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 必要吗?或者考虑到所有这些列都是主键的一部分,我甚至需要外键吗?

    谢谢。

    2 回复  |  直到 14 年前
        1
  •  1
  •   marc_s    14 年前

    如果在表B和表A之间已经有外键,以确保表B只包含值为 a_id 存在于表A中,则表C和表A之间的额外FK 阿伊德 是不必要的。当然,这需要表B和表A之间的FK关系是被加强、激活的,而不是以任何方式被禁用或规避。

    在表C和表B之间建立FK链接已经可以保证 TableC.a_id 只能引用的有效值为 阿伊德 (因为表B通过表B和表A之间的FK关系保证了这一点)。

        2
  •  3
  •   APC    14 年前

    首先,外键是断言父表中记录存在的必要条件,而主键则断言表中记录的唯一性。所以你两者都需要。

    一般来说,您希望避免使用复合主键。所以你的桌子应该是这样的:

    表A:A_id(pk)
    表B:B U id(pk),A U id(fk)
    表C:C_id(pk),B_id(fk)

    表C和表A之间不需要外键,因为表C和表B以及表B和表A之间的外键暗示了这种关系。

    编辑

    使用化合物有什么坏处 主键?

    在将表C连接到表B时,要键入的行数少了一行。而且在传播外键时,列数也会累积,因此表D将有一个由四列组成的复合主键。在某种程度上,这开始让人觉得很傻。我曾经做过一个系统 主键列和两个数据列。

    另一件事是,复合键也可以与业务键相关联。把它们作为外键传播是一件非常痛苦的事情。一旦我们决定对一个表使用代理(合成)键(autoincrement,sequence,guid,anything),一致性建议我们应该对所有表的主键使用相同的机制。

    有一些orm工具使得使用复合键变得困难。我没有提供不使用复合键的好理由,因为我强烈反对orm工具驱动我的数据模型的局限性,我只是指出了这一点。

    另一方面,使用复合键也有好处。我在一个系统上工作,在这个系统上我们必须对格式做很多查询

    select D.* 
    from  D 
        join A on ( D.a_id = A.id )
    where A.some_col = 'whatever'
    

    不必把表D和表C连接到表B就可以得到表A,这无疑是一个好消息。这对于实现虚拟专用数据库的数据库来说更为真实,因为他必须基于用户可以访问表A中的一个子集来限制对所有表的访问。

    所以这不是一条硬性规定。在争论的双方,人们对此都有强烈的感受。在我的职业生涯中,我一直大力支持复合主键,但现在我发现自己通常倾向于使用单列主键,在适当的时候,复合业务键会使用独特的约束来强制执行。

    简而言之,复合主键不是 错误的 只是太笨拙了。单列代理主键可能是行业标准。但是,在某些情况下,复合主键是正确的选择。