I have written this query which returns a users friends and the friends on those friends. As there is a lot of sub queries going on here I thought there much be a more efficient way of writing it, but it’s a bit beyond me.
users table
++++++++++++++++++
+ user_id + name +
++++++++++++++++++
+ 1 + bill +
+ 2 + bob +
+ 3 + sam +
+ 4 + ben +
++++++++++++++++++
user_friendships table
+++++++++++++++++++++++++++++++++++++
+ sender_user_id + receiver_user_id +
+++++++++++++++++++++++++++++++++++++
+ 1 + 2 +
+ 2 + 3 +
+ 4 + 2 +
+++++++++++++++++++++++++++++++++++++
The table is bi-directional so user 1 is a friend of user 2 and user 2 is a friend of user 1.
User 1 only has 1 friend user 2. User 2 has 2 friends, user 3 and user 4.
When the below query is run for user 1, user 2, 3 and 4 are returned.
query
SELECT * FROM users
WHERE ( user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id = '1'
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id = '1')
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id = '1'
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id = '1')
)
OR user_id IN
(SELECT receiver_user_id as user_id
FROM user_friendships
WHERE sender_user_id = '1'
UNION
SELECT sender_user_id as user_id
FROM user_friendships
WHERE receiver_user_id = '1')
)
AND user_id != '1'
To clarify the end result of the friends and friends of friends query should be a single list of user_ids so that it can be joined with the user’s table to retrieve the name etc
This could be helpfull: It tries to traverse the tables as few times as possible.