【问题标题】:Self join many-to-many relationship自加入多对多关系
【发布时间】:2023-03-03 19:51:01
【问题描述】:

根据下面的示例数据,假设 Julie (1) 有朋友 Adam、David、John (2, 3, 4)。 亚当 (2) 有朋友朱莉、大卫、约翰 (1, 3, 4)。

ID  Name
1   Julie
2   Adam
3   David
4   John
5   Sam

这会在一个表中建立自联接和多对多关系。

除了上述问题,假设 Julie (1) 将 Sam (5) 添加为好友,从技术和实践上讲,Sam (5) 现在也是 Julie (1) 的好友。这使事情变得更加复杂,因为关系是双向的。

所以我想知道:

  1. 如何设计数据库?
  2. 如何进行查询以返回每个用户的所有朋友?

谢谢!

【问题讨论】:

  • 自连接意味着表有一些东西要连接到自己。除了明显的“id=id”或“name=name”之外,您的表没有办法做到这一点,它们是简单/无用的连接。此表只是名称列表。它没有任何东西表明名字之间的友谊/联系。
  • @MarcB 正是我问“如何设计这样的数据库”的原因。 (即如何显示每个用户之间的关系)
  • 您需要第二张表来定义友谊。如果把朋友的朋友算作朋友,逻辑上可以推导出来,不需要记录,但你至少需要在第二张表中记录直接的友谊。
  • @ShWiVeL 所以在第二个表中,我需要双向记录吗? (即 1 是 2 的朋友,2 是 1 的朋友)。我在想类似的东西:ID FriendID 关系 1 2 朋友 2 1 朋友
  • 两种方式都记录会更容易查询,但不是必须的。例如,如果您记录 1 和 2,但忽略 2 和 1,我将尝试将一些东西放在一起,以便您查询它。

标签: sql sql-server


【解决方案1】:

示例数据:

PEOPLE

PERS_ID     PERS_NAME
1           Julie
2           Adam
3           David
4           John
5           Sam

FRIENDSHIPS

PERS_ID     FRIEND_ID
1           2
1           3
1           4
2           3
2           4

查询:

select people.pers_id    as person,
       people.pers_name  as person_name,
       peoplef.pers_id   as friend_id,
       peoplef.pers_name as friend_name
  from people
  join friendships
    on people.pers_id = friendships.pers_id
    or people.pers_id = friendships.friend_id
  join people peoplef
    on (peoplef.pers_id = friendships.pers_id and
       peoplef.pers_id <> people.pers_id)
    or (peoplef.pers_id = friendships.friend_id and
       peoplef.pers_id <> people.pers_id)
 order by 2, 4

SQL Fiddle 演示:http://sqlfiddle.com/#!2/97b41/6/0

无论您是否在友谊表上记录两个方向,这都会起作用。

【讨论】:

    【解决方案2】:

    非常同意其他人的观点。你需要一个链接表。我将提供更多详细信息。键和索引的一些示例以及您想要的查询(双向)。

        CREATE TABLE dbo.tblUser 
    (
        ID int identity(0,1),
        name varchar(20)
        CONSTRAINT PK_tblUser PRIMARY KEY (ID)
    )
    
    -- Many to many link table with FKs
    CREATE TABLE dbo.tblFriend 
    (
        ID1 int not null constraint FK_tblUser_ID1 foreign key references dbo.tblUser(ID), 
        ID2 int not null constraint FK_tblUser_ID2 foreign key references dbo.tblUser(ID)
        CONSTRAINT PK_tblFriend PRIMARY KEY (ID1, ID2)
    )
    
    -- Add index (So you can get an index seek if using ID2)
    CREATE INDEX IX_tblFriend_ID2 ON dbo.tblFriend (ID2)
    
    -- Test data
    INSERT INTO dbo.tblUser(name)
    VALUES ('Julie'),('Adam'),('David'),('John'),('Sam');
    
    Insert INTO dbo.tblFriend (ID1, ID2) 
    values(0, 1),(2, 0)
    
    
    -- Get bi-directional friend to friend relationships
    SELECT U1.Name as 'User1', U2.Name as 'User2' FROM dbo.tblFriend F 
        INNER JOIN dbo.tblUser U1 ON U1.ID = F.ID1
        INNER JOIN dbo.tblUser U2 ON U2.ID = F.ID2
    
    UNION
    
    SELECT U2.Name as 'User1', U1.Name as 'User2' FROM dbo.tblFriend F 
        INNER JOIN dbo.tblUser U1 ON U1.ID = F.ID1
        INNER JOIN dbo.tblUser U2 ON U2.ID = F.ID2
    
    ORDER BY User1, User2
    

    【讨论】:

      【解决方案3】:

      一种方法可能是您创建第二个存储人员和朋友 ID 的表。在这种情况下,请考虑下表。

      CREATE TABLE User 
          (
           id int auto_increment primary key, 
           name varchar(20)
          );
      
      CREATE TABLE Friend 
          (
           user_id int , 
           friend_id int      
          );
      
      INSERT INTO User
      (name)
      VALUES
      ('Julie'),
      ('Adam'),
      ('David'),
      ('John'),
      ('Sam');
      
      Insert INTO Friend
      (user_id, friend_id)
      values(1, 5),
      (3, 1);
      

      现在 Friend 表将存储 user_id 和他/她的friend_id。要获取特定用户的好友列表,您可以在这两列中的任何一列中搜索匹配的 id。以下是示例查询。

      -- Get Friends of Julie
      select 1 AS user_id, IF(user_id = 1, friend_id, user_id) AS friend_id
      FROM Friend
      WHERE user_id=1 OR friend_id=1;
      
      -- Get Friends of David
      select 3 AS user_id, IF(user_id = 3, friend_id, user_id) AS friend_id
      FROM Friend
      WHERE user_id=3 OR friend_id=3
      

      我希望您对此有所了解并可以尝试一下。

      【讨论】:

        【解决方案4】:

        我尝试了您在查询中写的任何内容:

        declare @table table  
        (
          id int,
          name varchar(40)
        )
        
        insert into @table values
        (1,   'Julie'),
        (2,   'Adam'),
        (3,   'David'),
        (4,   'John'),
        (5,   'Sam')
        
        select
        
        t1.name ,
        t2.name as friend
        
        from @table t1, @table t2 where t1.id <> t2.id
        and t1.id in (1,2) and t2.id <> 5
        order by t1.id
        

        【讨论】:

          猜你喜欢
          • 2013-06-17
          • 1970-01-01
          • 2011-08-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-04-21
          • 1970-01-01
          相关资源
          最近更新 更多