I am creating a small social network in which when a user posts anything.I will get ids of his friends to whom he referred the post.Now the problem is that the users who will be referred can be between 1 or 10. So now suppose that a user posted a status and referred 6 friends.
Now i need to find mutual friends between the user who posted the status and the people referred one by one.Meaning that suppose user who posted the status has id 1 and the people who are referred have 2,3,4,5,6,7.
So what the query will do it will find mutual friends between 1 and 2 then 1 and 3 then 1 and 4 and so on till 7.So at the end i will be getting a result containing the mutual friends between the user who posted and the people who are referred(or tagged we can say).
I've two tables User and Friends
User Table: Friends Table:
-------------------------- -----------------------------------
UserID Name friendsid friendname userid
-------------------------- -----------------------------------
1097517748 User1 3 friend1 536772587
100003052455644 User2 8 friend2 100003052455644
536772587 User3 8 friend3 1097517748
4 User4 3 friend4 100003052455644
Now the friends table can contain different people who does or does not exist in the user table.In this example user 2 and 3 has friend with id 8 in common.I've got my guy but that guy id i.e 8 must be present in the user table also.This is only between userid 2 and 3.
I will be getting several userid and i've find mutual friends of all the friends that are referred with the guy who has posted the status.
I hope I've cleared it.If I get the idea for the query I can generate it dynamically using php for different number of referred friends.
So far I've written this query.
SELECT count(f1.friendsid) FROM friends AS f1
INNER JOIN friends AS f2 ON f1.friendsid = f2.friendsid
WHERE f1.userid = 100003052455644
AND f2.userid = 1097517748
But this is only bringing me mutual friends between two user.When I add a third guy lets say f3 and compare it with f1 it does not bring any result and another problem with this query is that it is not verifying that the mutual friend id exists in the user table or not.After adding the 3rd guy.
SELECT count(f1.friendsid) FROM friends AS f1
INNER JOIN friends AS f2 ON f1.friendsid = f2.friendsid
INNER JOIN friends AS f3 ON f1.friendsid = f3.friendsid
WHERE f1.userid = 100003052455644
AND f2.userid = 1097517748
AND f3.userid = 536772587
This query does not bring any results.So I wanted to create a query that does all this.
EDIT:
Actually I am using facebook connect and I save all the users friends in my database when users login, the user table will contain only those users who are registered on my website.
I finally figured it out. The query was
SELECT DISTINCT(friendsid) FROM (
SELECT DISTINCT(f1.friendsid) FROM friends AS f1
INNER JOIN friends AS f2 ON f1.friendsid=f2.friendsid
and f1.userid = 100003052455644 and f2.userid =1097517748
INNER JOIN user ON f2.friendsid = user.userid and f1.friendsid = user.userid
UNION ALL
SELECT (f1.friendsid) FROM friends AS f1
INNER JOIN friends AS f2 ON f1.friendsid=f2.friendsid
and f1.userid = 100003052455644 and f2.userid =536772587
INNER JOIN user ON f1.friendsid = user.userid and f2.friendsid = user.userid
UNION ALL
SELECT DISTINCT(f1.friendsid) FROM friends AS f1
INNER JOIN friends AS f2 ON f1.friendsid=f2.friendsid
and f1.userid = 100003052455644 and f2.userid =694250830
INNER JOIN user ON f1.friendsid = user.userid and f2.friendsid = user.userid
) a
This query will find the id's of all the mutual friends between the user who posted the status and the users whom he refered.
The user with id 100003052455644 is the person who posted status and all the others are his friends whom he referred.The DISTINCT will make sure that the id's are unique and not repeated.This is for 3 persons he referred.We can add the UNION ALL part dynamically setting the id's and this will help us create a dynamic query for retrieving mutual friends for different number of referred people.
Related
Let's say I have a table called friends, and for each friendship, I add two entries. For example, if users 1 and 2 are friends, we will have:
uid1 uid2
----------
1 2
2 1
My goal is to find friends of friends, exclding the friends. The following query gives me friends of friends (including friends):
SELECT f2.uid2 FROM friends f1, friends f2 WHERE f1.uid1='YOUR_ID' AND f1.uid2=f2.uid1 AND f2.uid2!='YOUR_ID'
My preference is not to use IN or NOT IN. Can you think of anything to supplement this query?
Add an outer join with your own friends so you can filter them out.
SELECT f2.uid2 FROM friends f1
JOIN friends f2 ON f1.uid2 = f2.uid1
LEFT JOIN friends f3 ON f3.uid2 = f2.uid2 AND f3.uid1 = 'YourID'
WHERE f1.uid1='YourID'
AND f2.uid2!='YourID'
AND f3.uid2 IS NULL
SQLFIDDLE
You can do it with an additional join and aggregation:
SELECT f2.uid2
FROM friends f1 join
friends f2
on f1.uid1 = 'YOUR_ID' AND f1.uid2 = f2.uid1 AND f2.uid2 <> 'YOUR_ID'` join
friends f3
on f2.uid2 = f3.fuid1
GROUP BY f2.uid2
HAVING sum(f3.uid2 = 'YOUR_ID') = 0;
Im building a platform where users can connect with other users (Social platform)
I have a Table called friends and i am saving the connections like this
user_id | friend_id | request | add_date
Now i need to write a sql query to get the most recent friends a specific user's friends added that they are or not already friends of the user. Also the user must be accepted.
Think of it as a news feed and i was to see who my friends recently added (the new recently add person can be my friend or not)
So far i have this but works only when my friend added people i already have.
SELECT user_main_id AS frmname, friend_id AS type_id, add_date AS date
FROM friends
WHERE friend_id
IN
(SELECT friend_id
FROM friends WHERE (friend_id='$user_id' OR user_main_id='$user_id')
AND request=1 AND friend_id!=$user_id)
AND request=1 AND friend_id!=$user_id AND user_main_id!=$user_id
ORDER BY date DESC
Maybe there is a better why to approach this.
Suggestions? Much appreciated thanks. The connection is bilateral, no difference between user_id and friend_id. Was designed with those names and had to be carried forward.
Sample Record
96618 50683 1 2013-05-08 13:44:31
96618 1230 1 2013-04-03 18:28:51
11671 96618 1 2013-04-03 13:26:51
11671 1230 1 2013-03-23 18:26:08
Once 96618 connects with 50683 happens. users 11671 for example will get a msg saying your friend 96618 is now friends with 50683
Try this:
SELECT f2.friend_id
FROM friends f1 # Friends of target user
INNER JOIN friends f2
ON f1.friend_id = f2.user_id # Friends of their friends
AND f2.request = 1
AND f2.friend_id != f1.user_id
INNER JOIN friends f3 # Limiting it to mutual friends
ON f2.friend_id = f3.user_id AND f3.friend_id = f1.user_id
WHERE f1.user_id = 11671 AND f1.request = 1
ORDER BY f2.add_date DESC
Please note that with your current table structure, you are going to need two rows for each friendship, one for each direction. To do it with only one row, you probably want to split it into two tables - friendships and friendship_members.
I have looked through the questions but I cant find anything that does exactly what I need and I can't figure out how to do it myself.
I have 2 tables, a user table and a friend link table. The user table is a table of all my users:
+---------+------------+---------+---------------+
| user_id | first_name | surname | email |
+---------+------------+---------+---------------+
1 joe bloggs joe#test.com
2 bill bloggs bill#test.com
3 john bloggs john#test.com
4 karl bloggs karl#test.com
My friend links table then shows all relationships between the users, for example:
+--------=+---------+-----------+--------+
| link_id | user_id | friend_id | status |
+---------+---------+-----------+--------+
1 1 3 a
2 3 1 a
3 4 3 a
4 3 4 a
5 2 3 a
6 3 2 a
As a note the a in the status column means approved, there could also be r(request) and d(declined).
What I want to do is have a query where if a user does a search it will bring back a list of users that they are currently not already friends with and how many mutual friends each user has with them.
I have managed to get a query for all users that are currently not friends with them. So if the user doing the search had the user id of 1:
SELECT u.user_id,u.first_name,u.surname
FROM users u
LEFT JOIN friend_links fl
ON u.user_id = fl.user_id AND 1 IN (fl.friend_id)
WHERE fl.friend_id IS NULL
AND u.user_id != 1
AND surname LIKE 'bloggs'
How then do I have a count of the number of mutual friends for each returned user?
EDIT:
Just as an edit as I don't think I am being particularly clear with my question.
The query that I currently have above will produce the following set of results:
+---------+------------+---------+
| user_id | first_name | surname |
+---------+------------+---------+
2 bill bloggs
4 karl bloggs
Those are the users matching the surname bloggs that are not currently friends with joe bloggs (user id 1).
Then I want to have how many mutual friends each of these users has with the user doing the search so the returned results would look like:
+---------+------------+---------+--------+
| user_id | first_name | surname | mutual |
+---------+------------+---------+--------+
2 bill bloggs 1
4 karl bloggs 1
Each of these returned users has 1 mutual friend as joe bloggs (user id 1) is friends with john bloggs and john bloggs is friends with both returned users.
I hope this is a bit more clear.
Thanks.
Mutual friends can be found by joining the friend_links table to itself on the friend_id field like so:
SELECT *
FROM friend_links f1 INNER JOIN friend_links f2
ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person1
AND f2.user_id = $person2
But bear in mind that this, in its worst case, is essentially squaring the number of rows in the friend_links table and can pretty easily jack up your server once you have a non-trivial number of rows. A better option would be to use 2 sub-queries for each user and then join the results of those.
SELECT *
FROM (
SELECT *
FROM friend_links
WHERE user_id = $person1
) p1 INNER JOIN (
SELECT *
FROM friend_links
WHERE user_id = $person1
) p2
ON p1.friend_id = p2.friend_id
Also, you can simplify your friend_links table by removing the surrogate key link_id and just making (user_id,friend_id) the primary key since they must be unique anyway.
Edit:
How would this be applied to the original query of searching for users that aren't already friends, I would like to do both in a single query if possible?
SELECT f2.user_id, COUNT(*) 'friends_in_common'
FROM friend_links f1 LEFT JOIN friend_links f2
ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person
GROUP BY f2.user_id
ORDER BY friends_in_common DESC
LIMIT $number
I am also thinking that the user_id constraints can be moved from the WHERE clause into the JOIN conditions to reduce the size of the data set created by the self-join and preclude the use of subqueries like in my second example.
This query lists anyone who's not friend with user 1 and whose surname matches '%bloggs%':
SELECT
users.user_id,
users.first_name,
users.surname,
Sum(IF(users.user_id = friend_links_1.friend_id, 1, 0)) As mutual
FROM
users inner join
(friend_links INNER JOIN friend_links friend_links_1
ON friend_links.friend_id = friend_links_1.user_id)
ON friend_links.user_id=1 AND users.user_id<>1
WHERE
users.surname LIKE '%bloggs%'
GROUP BY
users.user_id, users.first_name, users.surname
HAVING
Sum(IF(users.user_id = friend_links.friend_id, 1, 0))=0
just change the user id on the ON clause, and the surname on the WHERE clause. I think it should work correctly now!
If A is friend of B, then B is also a friend of A? Wouldn't it be better to use just a link instead of two links (and instead of two rows in friends_links)? Then you have to use two status columns, status1 and status2, and A is friend of B only if status1 = status2 = "a".
There are many ways to show mutual friends, e.g.:
SELECT friend_id
FROM friend_links
WHERE friend_links.user_id = $user1 or friend_links.user_id = $user2
AND NOT (friend_links.friend_id = $user1 or friend_links.friend_id = $user2)
GROUP BY friend_id
HAVING Count(*)>1
And this query shows for each user and anyone who's not his/her friend:
SELECT
users.user_id,
users.first_name,
users_1.user_id,
users_1.first_name
FROM
users INNER JOIN users users_1 ON users.user_id <> users_1.user_id
WHERE
NOT EXISTS (SELECT *
FROM friend_links
WHERE
friend_links.user_id = users.user_id
AND friend_links.friend_id = users_1.user_id)
(The only think I didn't check is the friendship status, but it's easy to add that check).
I'm still working on it, but it's not easy to combine nicely these two queries togheter. So this isn't exactly an answer, I'm just showing some ideas that i've tried.
But what do you need exactly? A query that returns every user with anyone who's not his/her friend and the number of friends in common, or is the user_id already given?
With some code it's not a problem to answer your question... but there has to be a nice way just by using SQL! :)
EDIT:
I'm still wondering if there's a better solution to this, in particular the next query could be extremely slow, but it looks like this might work:
SELECT
users_1.user_id,
users_2.user_id,
Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links_1.friend_id, 1, 0)) As CommonFriend
FROM
users users_1 INNER JOIN users users_2
ON users_1.user_id <> users_2.user_id,
(friend_links INNER JOIN friend_links friend_links_1
ON friend_links.friend_id = friend_links_1.user_id)
GROUP BY
users_1.user_id,
users_2.user_id
HAVING
Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links.friend_id, 1, 0))=0
(as before, i didn't check friendship status)
If user is given, you could put WHERE users_1.user_id=$user1 but it's better to just leave one user table, and filter the next INNER JOIN whith that user.
I need help querying the friendID from a table.
My table stores the user id of two members who are friends together.
But in order to store a "friendhship" b/w two members I would have to store two records like this:
friendshipID | userID | friendID
1 | 5 | 10
2 | 10 | 5
Yet, that seems heavy for the DB when we really only need to store the first record as that is sufficient as it contains both ids of both members.
However, the trouble comes when I want to query the records of the friends of ID=5. Sometimes the ID is in the userID column and other times it is in the friendID column.
This is the query I am using:
SELECT *
FROM friends
WHERE userID = '5'
OR friendID = '5'
But what I want to do is something like this
SELECT
if $userID=5 then userID as myfriend
else friendID=5 then friendID as myfriend
FROM friends WHERE userID='5' OR myfriendID='5'
Hope that makes sense. In the end I would like to have all the friends ID's of member #5 and not bring up results with #5 as the friend or user....but just his friends.
This query would return the Id value, and name, of the friends of #5 as shown in this SQL Fiddle Example
SELECT f.FriendId AS FriendId
, u.Name AS FriendName
FROM FriendTable AS f
INNER JOIN UserAccount AS u ON f.FriendId = u.UserId
WHERE f.UserId = 5
UNION
SELECT f.UserId AS FriendId
, u.Name AS FriendName
FROM FriendTable AS f
INNER JOIN UserAccount AS u ON f.UserId = u.UserId
WHERE f.FriendId = 5
The UNION will remove duplicates, making this query work for both a single record of friends, or the 2 record friendship you mention in the comment. You shouldn't need the 2 record friendship though, because there is no new information being stored in the second record that you cannot get from only having one record.
I have a database table called users with a primary key of user_id for each user.
I also have a table called friends with two fields, user_id and friend_user_id.
The user_id field is always the lowest of the two user_id's in order to avoid duplicate entries.
Say I have two users in mind, (lets say user id 1 and user id 4 although they could be anything).
How would I return all rows from the users table for users that are friends with user 1 and user 4 (i.e mutual friends)?
I will give you the recipe:
Find all friends of user 1
Find all friends of user 2
Intersect them and the result will be the mutual friends.
Much like this:
UPDATE: Here's the query:
select f.friend_user_id from friends f where f.friend_user_id in (
select friend_user_id from friends where user_id=<id_of_user_a>)
and f.user_id=<id_of_user_b>
The ids returned by above query will be the id of all the users that are mutual friends of user_a and user_b. If you want to get all the details (name, etc) about those users, then do this:
select f.friend_user_id,u.* from friends f inner join users u
on u.user_id=f.friend_user_id
where f.friend_user_id in (
select friend_user_id from friends where user_id=<id_of_user_a>)
and f.user_id=<id_of_user_b>
SELECT friends.friend_user_id FROM user, friends
INNER JOIN friends ON friends.user_id = user.user_id
WHERE user.user_id = 1
AND friend.friend_user_id
IN (SELECT friends.friend_user_id
FROM user, friends
INNER JOIN friends ON friends.user_id = user.user_id
WHERE user_id = 4)