如何在pgsql中获得朋友的朋友

如何在pgsql中获得朋友的朋友,sql,postgresql,Sql,Postgresql,我正在创建一个友谊模型模式 这是表的结构 --PostgreSQL 9.6 --'\\' is a delimiter create table user_list( id bigserial primary key, first_name text not null, last_name text, avatar_url text ); create table friendship ( id bigserial primary key,

我正在创建一个友谊模型模式

这是表的结构

--PostgreSQL 9.6
--'\\' is a delimiter


create table user_list(
    id bigserial primary key,
    first_name text not null,
    last_name text,
    avatar_url text
);


create table friendship (
    id bigserial primary key,
    user_id bigint not null,
    friend_user_id bigint not null,
    CONSTRAINT fk_friend1
      FOREIGN KEY(user_id) 
      REFERENCES user_list(id),
      
     CONSTRAINT fk_friend2
      FOREIGN KEY(user_id) 
      REFERENCES user_list(id)
);
还有一些记录

insert into user_list(id,first_name,last_name,avatar_url) values(1,'Sunny',null,null),(2,'Dev',null,null),(3,'Ram',null,null),(4,'Prinka',null,null),
(5,'Neha',null,null);

insert into friendship(id,user_id,friend_user_id) values(1,1,3),(2,1,2),(3,2,3),(4,2,5),(5,5,1);
所以友谊表维持着这种关系。如果user1是user2的朋友,我们将在友谊表user1、user2中插入一条记录

这表示user1是user2的朋友,反之亦然

所以通过搜索user2的友谊,应该返回user1

查询以获取用户的朋友此操作正常

-- get frieds of user
SELECT distinct(u.id) as friend_id,u.first_name FROM friendship AS f , user_list AS u WHERE 
CASE WHEN f.user_id = 1 THEN f.friend_user_id = u.id WHEN
f.friend_user_id = 1 THEN F.user_id = u.id END;
现在,如果我想获得用户朋友的朋友,我正在尝试这个嵌套查询

-获取好友的好友好友用户的共同好友

SELECT distinct(t.friend_id) as friend_id,t.first_name FROM 
(SELECT distinct(u.id) as friend_id,u.first_name FROM friendship AS f , user_list AS u WHERE 
CASE WHEN f.user_id = 1 THEN f.friend_user_id = u.id WHEN
f.friend_user_id = 1 THEN F.user_id = u.id END) as t,friendship as f2
where 

CASE WHEN f2.user_id = t.friend_id THEN f2.friend_user_id = t.friend_id WHEN
f2.friend_user_id = t.friend_id THEN f2.user_id = t.friend_id END;
连我都试过了

SELECT DISTINCT u3.friend_user_id FROM friendship u1
   JOIN friendship u2 ON u1.friend_user_id = u2.user_id
   JOIN friendship u3 ON u2.friend_user_id = u3.user_id
   WHERE u1.user_id = 1;
但这两个查询都不起作用。有什么帮助吗

还有没有其他方法可以通过优化的方式获得用户的朋友

这里是在线pgsql工具,可以尝试一下


我认为这可以通过一个联合和一些情况来实现,但是我建议在友谊表中始终存储2条记录,如果用户1是用户2的朋友,那么应该有记录1,2和2,1

此查询还可以包括直接朋友,因为朋友的朋友也可以是直接朋友

解释 查询分为两部分,让我们参加第1部分:

select distinct case when f1.friend_user_id = f2.user_id then f2.friend_user_id
    when f1.friend_user_id = f2.friend_user_id then f2.user_id 
from friendship f1
left join friendship f2
    on f1.friend_user_id = f2.user_id
    or f1.friend_user_id = f2.friend_user_id
where f1.user_id = 1
这将获得所有友谊f1,其中用户1要求其他用户成为朋友,即1,2,1,3,但不是5,1。然后我们再次加入友谊表,参考f2,以获得朋友的朋友。朋友的朋友由f1.friend\u user\u id=f2.user\u id加入,或由f1.friend\u user\u id=f2.user\u id加入。这将得到2,5

第2部分的工作方式相同,只是从要求用户1成为朋友的用户开始,即5,1,并从何处开始


同样,如果始终两个条目都可以表示,那么整个查询可以大大简化,因此1,2和2,1。

下面的递归cte应该为您完成这项工作

with recursive cte as 
(
select  ul.id, fd.friend_user_id from friendship fd 
 join user_list ul on ul.id=fd.user_id 
 where ul.id = 1
union all 
select ul.id, fd.friend_user_id from friendship fd 
 join cte on cte.friend_user_id = fd.user_id 
  join user_list ul on ul.id=fd.user_id 
where  fd.friend_user_id <>1
)
select distinct friend_user_id from cte
您可以阅读有关递归cte的更多信息


递归cte可能会进入无限循环,请确保您添加了条件以避免出现这种情况,就像我添加了fd.friend\u user\u id 1一样。

您可以解释查询吗?添加了解释吗
with recursive cte as 
(
select  ul.id, fd.friend_user_id from friendship fd 
 join user_list ul on ul.id=fd.user_id 
 where ul.id = 1
union all 
select ul.id, fd.friend_user_id from friendship fd 
 join cte on cte.friend_user_id = fd.user_id 
  join user_list ul on ul.id=fd.user_id 
where  fd.friend_user_id <>1
)
select distinct friend_user_id from cte