简体   繁体   English

PostgreSQL选择您可能认识的人,按照共同的朋友数量排序

[英]Postgresql select people you may know orderded by number of mutual friends

I'm building a social network, and I want my members to be able to easily find new friends. 我正在建立一个社交网络,我希望我的会员能够轻松找到新朋友。 Just like in Facebook, I want to suggest them some people they may know by the number of mutual friends they have. 就像在Facebook上一样,我想向他们推荐一些他们可能会认识的人,他们的共同朋友数量很多。

My PostgreSQL database structure for friendships is as following: 我的PostgreSQL友谊数据库结构如下:

> PROFILES_FRIENDSHIPS
> ----------------------
> - fri_profile_from // int, Person who sent the friendship request
> - fri_profile_to // int, Person who received the friendship request
> - fri_accepted // tinyint, has the person accepted the friendship request?

This is the query I figured out in PostgreSQL for finding the number of mutual friends between 2 profiles (profile with ID 24, and profile with ID 26): 这是我在PostgreSQL中发现的查询,用于查找2个配置文件(ID为24的配置文件和ID为26的配置文件)之间的共同好友数:

SELECT COUNT(*)
FROM profiles AS p
INNER JOIN (
        SELECT (
        CASE    WHEN ( 26 = f.fri_profile_from ) THEN f.fri_profile_to 
                    ELSE f.fri_profile_from END) AS fri_profile_from 
        FROM profiles_friendships AS f 
        WHERE 1 = 1
        AND (f.fri_profile_to = 26 OR f.fri_profile_from = 26) 
        AND fri_accepted = 1) 
AS f1 
ON (f1.fri_profile_from = p.pro_id) 
INNER JOIN (
        SELECT (
        CASE    WHEN ( 24 = f.fri_profile_from ) THEN f.fri_profile_to 
                    ELSE f.fri_profile_from END) AS fri_profile_from 
        FROM profiles_friendships AS f 
        WHERE 1 = 1
        AND (f.fri_profile_to = 24 OR f.fri_profile_from = 24) 
        AND fri_accepted = 1) 
AS f2 
ON (f2.fri_profile_from = p.pro_id)

Now I have been trying to convert this query to make it find the profiles with the most mutual friends of me, but who are not friends with me. 现在,我一直在尝试转换此查询,以使其与我之间最共同的朋友,但又不是我的朋友,找到个人资料。 But without success... I also researched a lot of examples on this website, but most them are working with double records in the friendships table. 但是没有成功……我还在这个网站上研究了很多例子,但是大多数例子都在友谊表中使用了双记录。 Like if 24 is friends with 26, there are 2 records: (24, 26) and (26, 24). 就像24是26的朋友一样,有2条记录:(24,26)和(26,24)。 That makes them easier to join and to find mutual friends, but that's not how I want to build my database. 这使他们更容易加入并找到共同的朋友,但这不是我想要构建数据库的方式。

If someone could help me to get started on this query, I would be very grateful. 如果有人可以帮助我开始这个查询,我将不胜感激。

Step 1 Get everyone that isnt a friend 第1步:让所有不是朋友的人

Select * 
From profiles
where (from/to_friendship is not myID)

step 2 include a column with # of mutual friends and order by it 第2步包括一个包含#个共同朋友的列,并按其排序

select *, 
  (select count(*) from [mutual friends query]) as NrOfMutualFriends)
From profiles
where (from/to_friendship is not myID)
Order by NrOfMutualFriends

Edit: Mutual Friends query: 编辑:共同的朋友查询:

Step 1 select all my friends and all his friends 步骤1选择我所有的朋友和他的所有朋友

select if(from = myId, to, from) as myfriendids
from PROFILES_FRIENDSHIPS where from = myid or to = myid

select if(from = hisId, to, from) as hisfriendids
from PROFILES_FRIENDSHIPS where from = hisId or to = hisId

Step 2 Combine these queries into 1 步骤2将这些查询合并为1

select count(*) 
from 
  ( select if(from = myId, to, from) as myfriendids
    from PROFILES_FRIENDSHIPS where from = myid or to = myid) myfriends
inner join 
  ( select if(from = hisId, to, from) as hisfriendids
  from PROFILES_FRIENDSHIPS where from = hisId or to = hisId) hisfriends
on myfriendsids = hisfriendsids
WITH friends AS(
  SELECT p.pro_id, CASE WHEN f.fri_profile_from = p.pro_id THEN f.fri_profile_to 
                    ELSE f.fri_profile_from END AS friend_id
  FROM profiles
)
SELECT f2.pro_id, count(*) as friend_count
FROM friends AS f1
  JOIN friends AS f2
    ON f1.friend_id=f2.friend_id
       AND f1.pro_id != f2.pro_id
       AND f1.pro_id != f2.friend_id
WHERE f1.pro_id = :user_id
GROUP BY f2.pro_id
ORDER BY friend_count;

you can easily create inline view in double records format: 您可以轻松创建双重记录格式的内联视图:

with cte_friends(user_id, friend_id) as (
    select
        fri_profile_from, fri_profile_to
    from PROFILES_FRIENDSHIPS
    where fri_accepted = 1

    union all -- or union if there could be duplicates

    select
        fri_profile_to, fri_profile_from
    from PROFILES_FRIENDSHIPS
    where fri_accepted = 1
)
select
    f2.friend_id, count(distinct f2.user_id)
from cte_friends as f1
    inner join cte_friends as f2 on f2.user_id = f1.friend_id
    left outer join cte_friends as f3 on f3.user_id = f2.friend_id and f3.friend_id = f1.user_id
where
    f1.user_id = 1 and f3.user_id is null and
    f2.friend_id != 1
group by f2.friend_id
order by 2 desc

sql fiddle demo sql小提琴演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM