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

复合主键包含两个引用同一表的外键:SQLServer和MySQL

  •  3
  • asfsadf  · 技术社区  · 15 年前

    我已经阅读了很多关于DB表设计的文章,这些设计是针对一对多/用户对朋友的场景。一个员额包括:

    用户

    * user_id (primary key)
    * username
    

    * user_id (primary key, foreign key to USERS(user_id))
    * friend_id (primary key, foreign key to USERS(user_id))
    

    >但不会停止 因为(2,1)是有效的。 只有一个例子

    粗体部分促使我提出我的问题:SQLServer和MySQL如何处理这些类型的复合键有区别吗?两者是否都需要海报提到的触发器,以确保独特性?

    我问这个问题,因为到目前为止,我一直在SQLServer中使用类似的表结构,没有任何这样的触发器。我是不是幸运地没有遇到这条潜伏在草丛中的数据复制蛇?

    4 回复  |  直到 15 年前
        1
  •  5
  •   Thomas    15 年前

    是的,所有的数据库管理系统都会这样处理。原因是DBMS假定列有意义。也就是说,元组不是由无意义的数字组成的。每个属性都有意义。 user_id 被认为与 friend_id . 因此,设计者有责任建立一个规则,声称1,2等于2,1。

        2
  •  2
  •   Martin Smith    15 年前

    你可以使用一个check约束 friend_id > user_id 防止“逆转”。这将强制执行不可能输入一对,例如 (2, 1) 这样的关系必须作为 (1, 2)

        3
  •  2
  •   Quassnoi    15 年前

    如果你的友谊关系是对称的,你需要添加一个 CHECK(user_id < friend_id) 在表定义中插入如下数据:

    INSERT
    INTO    friends
    VALUES  (
            (CASE user_id < friend_id THEN user_id ELSE friend_id END),
            (CASE user_id > friend_id THEN user_id ELSE friend_id END)
            )
    

    SQL Server ,您可以构建 UNIQUE

    CREATE TABLE friends (orestes INT, pylades INT, me AS CASE WHEN orestes < pylades THEN orestes ELSE pylades END, friend AS CASE WHEN orestes > pylades THEN orestes ELSE pylades END)
    
    CREATE UNIQUE INDEX ux_friends_me_friend ON friends (me, friend)
    
    INSERT
    INTO    friends
    VALUES  (1, 2)
    
    INSERT
    INTO    friends
    VALUES  (2, 1)
    -- Fails
    

    要获取给定用户的所有好友,需要运行以下查询:

    SELECT  friend_id
    FROM    friends
    WHERE   user_id = @myuser
    UNION ALL
    SELECT  user_id
    FROM    friends
    WHERE   friend_id = @myuser
    

    然而,在 MySQL ,则始终保留每对的两个副本可能更有效。

    你可能会发现这些文章很有趣:

        4
  •  2
  •   Charles Bretana    15 年前

    如果关系是对称的,那么另一种选择是在数据库中将关系“定义”为非对称的,但是每次添加任何一个元组时,总是添加两个元组。

    你基本上是在说“友谊的本质是在数据库不对称,A可以是B的朋友,而B不是A的朋友,但应用程序总是会添加(或删除)两个记录(A,B)和(B,A),每当我添加(删除)。这也简化了查询逻辑,因为您不必再同时查看这两列。每次修改数据时都会有一个额外的插入/删除操作,但查询时读取次数会减少。。。