【问题标题】:how to represent symmetric many to many relationship如何表示对称的多对多关系
【发布时间】:2018-11-07 19:37:38
【问题描述】:

假设我有一个名为 USER 的实体,并且两个 USER 之间存在关系 FRIENDSHIP 所以为此我有一个表'USER'和一个关系表'FRIENDSHIP'

用户 id 名字姓氏 1 塔赫尔查布拉瓦拉 2 约翰·杜萨 3 拉胡尔·辛格 4 迪帕克·帕特尔

友谊 身份证号码 1 2 1 3 1 4 4 1 4 3

在上表中,我存储了两次相同的信息,即“taher 是 deepak 的朋友,而 deepak 是 taher 的朋友”

有没有办法减少这种冗余?

【问题讨论】:

    标签: database-design


    【解决方案1】:

    好吧,您当然可以假设所有友谊都是对称的,并且只存储一次该友谊,但这意味着当您要查询 Taher 的所有朋友时,您必须在任一列中查找他的 ID。

    或者,您可以有一个单独的关系 ID 表,然后是一个与用户的一对多关系表。这样做的好处是,如果有一天你想要的话,它可以允许多人关系,并且可以让你添加关于关系的元数据(什么时候开始的,谁建议的,等等)。

       User                
    Id    Name          
    1     Taher         
    2     Deepak        
    
    Relationship              
    Id     StartDate           
    1      2010-08-23
    
    UserRelationship
    RelationshipId UserId
    1                1
    1                2
    

    另一方面,例如,在 Facebook 上,我可以“加好友”某人,而他们可以决定不回复我的好友。如果您没有现在使用的“冗余”方法,您将如何表示这种尚未互惠的友谊?

    【讨论】:

    • 酷我从来没有想过多人场景但是对于两个人的场景我认为这会更合适RelationshipId|用户 ID | User2_Id 你怎么看?我真的很喜欢这种方法,谢谢
    • 如果把 User1 和 User2 列放在同一行,你真的回到了起点:如果你想找到 Taher 的所有朋友,你必须寻找每一行有 Taher 的作为 User1 或 User2 的 ID。
    【解决方案2】:

    制定一条规则,例如“第一个 ID 值始终低于第二个 ID 值”,这样可以确保没有重复。

    在这种情况下,对 (4,1) 无效,对 (4,3) 将存储为 (3,4)。

    【讨论】:

      【解决方案3】:

      显而易见的解决方案是每对朋友只存储 1 条记录。但是,保持唯一性变得更加困难;与“冗余”解决方案相比,获取/更新/删除朋友关系的所有查询都变得更加复杂。此外,具有 2 条记录的解决方案允许您维护好友请求(例如,UserA 要求 UserB 成为好友。UserB 可以确认或拒绝此请求)。所以我想说冗余在这种情况下是完全有效的。

      【讨论】:

        【解决方案4】:

        如果您存储这两行,则需要强制执行完整性规则,以确保友谊始终成对出现。

        在表中只存储一行(比如,FR),并创建一个视图 SYMFR 为

        从 FR 中选择 x,y 联盟 选择 x 作为 y,y 作为 x FROM FR

        【讨论】:

          【解决方案5】:

          如果您确实决定使用对称设计,那么确保每个友谊始终是双向的可能会很有用。你可以试试这个:

          CREATE TABLE Friendship
           (UserId1 INT NOT NULL REFERENCES Users (UserId),
            UserId2 INT NOT NULL,
            PRIMARY KEY (UserId1, UserId2),
            FOREIGN KEY (UserId2, UserId1) REFERENCES Friendship (UserId1, UserId2));
          
          INSERT INTO Friendship (UserId1, UserId2)
          VALUES (1,2),(2,1);
          

          【讨论】:

          • 嗯,我喜欢这个主意。但是你不能插入行。
          • 否,约束逐行检查。 innodb_version | 5.7.24 |版本 | 5.7.24-0ubuntu0.18.04.1 插入友谊(UserId1,UserId2)值(1,2),(2,1);错误 1452 (23000): 无法添加或更新子行:外键约束失败 (tests.Friendship, CONSTRAINT Friendship_ibfk_1 FOREIGN KEY (UserId2, UserId1) 参考Friendship (@987654328 @, UserId2))
          • @Pierre-OlivierVares,确实如此。它适用于大多数 SQL DBMS,但不适用于 MySQL。但很多事情都是如此,没有人要求特定于 MySQL 的解决方案。
          • 确实,你是对的,我认为它是 MySql(因为那是我正在寻找的)。我真的很惊讶它可以在任何 DBMS 中工作 - 但我显然错了:我在 sqlfiddle.com 中尝试过,它确实在(至少)PostgreSql 9.6 和 Oracle 中工作(使用 SELECT 1,2 FROM DUAL UNION SELECT 2 ,1 FROM DUAL 而不是多个 VALUES)
          猜你喜欢
          • 2013-03-08
          • 1970-01-01
          • 2021-10-11
          • 1970-01-01
          • 2021-01-28
          • 2015-07-15
          • 2018-12-24
          • 2017-08-25
          • 1970-01-01
          相关资源
          最近更新 更多