I'm looking for a query to create a table in MySQL with the degree of seperation between two users. I already found Degrees of Separation Query.But that will, if i understand correctly, result in a recommended friendlist with mutual friends. What i'm looking for is slightly different.
I have a table with "friends" between users (contains no duplicate relations like 1 to 2 & 2 to 1).
friends
(id
,initiator_user_id
,friend_user_id
,is_confirmed
)
What i am trying to create is a table with all relations between friends, friends of friends and FoFoF. like this:
relation_degrees
(id
,first_user_id
,second_user_id
,relation_degree
)
so the relation_degree column only contains the value 1 (friends), 2 (FoF) and 3 (FoFoF).
I was able to do it in Excel, but there my friends where stored in a matrix, which make calculations IMO a little bit easier. I hope somebody will be able to give me a hint to do the same in MySQL.
Thanks!!
edit: with the help from Fluffeh i found the following solution to my problem.
`Create table degree_two select mb.user as User, mb.friend as Friend, min(mb.rel) as relation_degree
from ( select 1 as rel, fr1.User, fr1.Friend from degree_one fr1
union all select 2 as rel, fr2.User, fr3.Friend from degree_one fr2 left outer join degree_one fr3 on fr2.Friend=fr3.User ) mb Where user <> friend group by mb.User, mb.Friend
Create table degree_three select mb.user as User, mb.friend as Friend, min(mb.relation_degree) as relation_degree from ( select fr1.relation_degree, fr1.User, fr1.Friend from degree_two fr1 union all select 3 as rel, fr2.User, fr3.Friend from degree_two fr2 left outer join degree_one fr3 on fr2.Friend=fr3.User ) mb Where `user` <> `friend` group by mb.User, mb.Friend
It is kind of a work around but it gives me the desired output. I'm still wondering why the query from fluffeh doesn't work correctly, because i really want a single query as solution. i will continue fooling around with the query... I hope that somebody can help me merging these query into one.
This query gave me the desired solution result:
Create table degree_two
select
mb.user as User,
mb.friend as Friend,
min(mb.rel) as relation_degree
from
(
select
1 as rel,
fr1.User,
fr1.Friend
from
degree_one fr1
union all
select
2 as rel,
fr2.User,
fr3.Friend
from
degree_one fr2
left outer join degree_one fr3
on fr2.Friend=fr3.User
where fr2.user <> fr3.friend
union all
select
3 as rel,
fr4.user,
fr6.Friend
from
(degree_one fr4
left outer join degree_one fr5
on fr4.friend=fr5.user
and fr4.user <> fr5.friend
left outer join degree_one fr6
on fr5.friend = fr6.user
and fr5.user <> fr6.friend)
where fr6.friend IS NOT NULL
) mb
group by
mb.User,
mb.Friend
Thanks Fluffeh for your help!
You can do this with outer joins back to the table itself...
select
mb.initiator_user_id as first_user_id,
mb.friend_user_id as second_user_id,
mb.rel as relation_degree
from
(
select
1 as rel,
fr1.initiator_user_id,
fr1.friend_user_id
from
friends fr1
union all
select
2 as rel,
fr2.initiator_user_id,
fr3.friend_user_id
from
friends fr2
left outer join friends fr3
on fr2.friend_user_id=fr3.initiator_user_id
// and again etc or in a code loop (not really done these much)
) mb
Basically, it seems you have the IDs able to be linked from friend1 to friend2, but the structure also allows for a query that allows friend1 to use friend2 to see who THEIR friends are - you can union these results with the degree easily enough.
Edit: Resolving issues based on comment:
select
mb.initiator_user_id as first_user_id,
mb.friend_user_id as second_user_id,
min(mb.rel) as relation_degree
from
(
select
1 as rel,
fr1.initiator_user_id,
fr1.friend_user_id
from
friends fr1
where is_confirmed = 1
union all
select
2 as rel,
fr2.initiator_user_id,
fr3.friend_user_id
from
friends fr2
left outer join friends fr3
on fr2.friend_user_id=fr3.initiator_user_id
and fr3.is_confirmed = 1
// and again etc or in a code loop (not really done these much)
) mb
group by
mb.initiator_user_id,
mb.friend_user_id
Edit: Adding third layer of relationships based on comment:
select
mb.initiator_user_id as first_user_id,
mb.friend_user_id as second_user_id,
min(mb.rel) as relation_degree
from
(
select
1 as rel,
fr1.initiator_user_id,
fr1.friend_user_id
from
friends fr1
where is_confirmed = 1
union all
select
2 as rel,
fr2.initiator_user_id,
fr3.friend_user_id
from
friends fr2
left outer join friends fr3
on fr2.friend_user_id=fr3.initiator_user_id
and fr3.is_confirmed = 1
union all
select
3 as rel,
fr4.initiator_user_id,
fr5.friend_user_id
from
friends fr3
left outer join friends fr4
on fr3.friend_user_id=fr4.initiator_user_id
and fr4.is_confirmed = 1
left outer join friends fr5
on fr4.friend_user_id=fr5.initiator_user_id
and fr5.is_confirmed = 1
// and again etc or in a code loop (not really done these much)
) mb
group by
mb.initiator_user_id,
mb.friend_user_id