I'd like to firstly point that I'm not very good at advanced MySQL just yet. So please forgive me. What I am trying to do is create a friends list like what's in the image below:
Here is my db structure:
friends table:
users table:
Here is my code so far:
<?php $query3 = $this->db->query("SELECT * FROM friends WHERE node1id = '{$myuserid}'");
foreach($query3->result() as $row1) {
echo $row1->node1id."<br>"; } ?>
I know this code isn't logically correct. What I am trying to do is pull in the users table. And if relationType = friends, display firstname and lastname of the user in the friends list. I have two variables. $selectedId and $myuserid. $selectedId is the id of the profile the user is viewing. and $myuserid is the id of the logged in user. How would I code this type of feature logically?
SELECT username FROM users
WHERE userid IN
(SELECT node2id FROM friends WHERE node1id = '{$myuserid}'
AND relationType = 'friends')
and
echo $row1->username
For mutual friends you could do this
EDIT: Just realised last version of this wasn't right, fixed now (untested)
SELECT username FROM users
WHERE userid IN
(SELECT node2id FROM (
(SELECT node2id FROM friends WHERE relationType = 'friends' AND node1id <> '{$myuserid}' AND node1id IN
(SELECT node2id FROM friends WHERE relationType = 'friends' AND node1id = '{$myuserid}')))
WHERE node2id IN (SELECT node2id FROM friends WHERE relationType = 'friends' AND node1id = '{$myuserid}'))
This first selects friends, then it selects the friends of those friends which is not equal (not equal is <>) to yourself. It then only selects from that list the friendIDs which match your your own friend IDs. It then selects the name of these users from the users table.
You can do a select inside of a select like below:
SELECT * FROM users WHERE idusers IN (
SELECT node2id FROM friends WHERE node1id = $myUserId
)
Here's how to get all friends of a particular user ($selectedid), and determine whether or not each of their friend is a mutual friend:
SELECT b.*,
c.myfrnd IS NOT NULL AS isMutual
FROM (
SELECT IF(node2id = '$selectedid', node1id, node2id) AS usrfrnd
FROM friends
WHERE '$selectedid' IN (node1id,node2id) AND
relationType = 'friends'
) a
JOIN users b ON a.usrfrnd = b.userid
LEFT JOIN (
SELECT IF(node2id = '$myuserid', node1id, node2id) AS myfrnd
FROM friends
WHERE '$myuserid' IN (node1id,node2id) AND
relationType = 'friends'
) c ON b.userid = c.myfrnd
ORDER BY isMutual DESC
The column isMutual will contain 1 if the friend is a mutual friend, otherwise 0 if not. Mutual friends show up first in the result set.
The thing you have to consider is that a user could be in either columns node1id or node2id, so in order to get a consistent join, we use a subselect to force the friends of the parameter userids ($selectedid and $myuserid) to be in the same column.
Let me know how this works.
Related
I have tables:
likes - id, user_id, like_user_id<br>
users - id, name, email ...,<br>
friends - id, user_id, friend_id, status<br>
Is it possible to sort it with one SQL query first to show the friends then the other users.
Any help would be appreciated.
Thank you.
I tried this and it works, but the problem is it give me double results of users:
select *
from `likes`
left join `users` on `users.id` = `likes.user_id`
left join `friends` on `friends.user_id` = `likes.user_id`
or `friends.friend_id` = `likes.user_id`
where `likes.id` = 1
order by `friends.user_id` = 5
or `friends.friend_id` = 5
You need to work with a UNION here to merge the liked users with the befriended users. Upon doing this, you can create an artificial column friend, that you fill with 1 in the friend query and 0 in the like query. Later on you can order by that column.
SELECT
friends.user_id,
1 as friend,
users.*
FROM
friends
JOIN users ON users.id = friends.friend_user_id
UNION SELECT
likes.user_id,
0 as friend,
users_liked.*
FROM
likes
JOIN users as users_liked ON likes.like_user_id = users_liked.id
WHERE
user_id = '$userId'
ORDER BY friend DESC, id ASC
This will return a list of all friends, followed by a list of all liked users.
I'm trying to make a homepage somewhat like Facebook, I made it so it could show the posts from the people I follow, but I couldn't see my own posts as I can't follow myself. Here is the line of SQL code I've written (it contains PHP variables):
SELECT *
FROM user_posts
INNER JOIN user_following ON user_posts.username = user_following.username
WHERE user_following.follower = '$me->username'
ORDER BY id DESC
LIMIT 0, 15
The user_posts table contains all the posts.
The user_following table contains all follow data, where username is the user being followed, and the follower is the user following the username
$me->username is the username of the user logged in.
user_posts table structure:
user_following table structure:
Thanks, in advance!
There's a couple of different ways to skin this query:
Sub-query
SELECT *
FROM user_posts
WHERE user_posts.username = 'bob'
OR user_posts.username IN(
SELECT username
FROM user_following
WHERE user_posts.username = user_following.username
)
LIMIT 0, 15
http://sqlfiddle.com/#!9/6bf2c6/9
Use the Users Table
Requires GROUP BY or DISTINCT user_posts.id, which are non-optimal.
SELECT
user_posts.*
FROM users
LEFT JOIN user_following ON users.username = user_following.username
INNER JOIN user_posts ON (
users.username = user_posts.username
OR user_following.follower = user_posts.username
)
WHERE users.username = 'bob'
GROUP BY user_posts.id
LIMIT 0, 15
http://sqlfiddle.com/#!9/d91be/1
IMPORTANT! Make sure and index those columns in your table. Otherwise, performance will suffer as the tables get bigger (especially user_following).
Try this code:
select *
from user_posts up
join user_following uf on up.username = uf.username
where uf.follower = '$me->username'
or up.username = '$me->username'
How we can do something as follows?
$results = $DB->query("SELECT * FROM users WHERE id!='{$id}' ");
Even I don't know to code,
$a = $DB->query("SELECT * FROM friends WHERE(someone is not friends with you)' ");
Columns in friends: user_id, friends_id
$DB->query("SELECT x.* FROM users x WHERE x.id NOT IN (myid, friendids)");
Use NOT IN
ID NOT IN (IDs OF FRIEND)
Example
$DB->query("SELECT * FROM user AS User WHERE User.id NOT IN (select * from friends where user_id = User.id)");
You need to get the persons whom are not your friends. right?
So you have your user_id as $my_id. Then you can select the friend_ID's from friends for whom the user_id field does not contain your user_id value($my_id). Then from those friend_ID's retrieved, you can select the users from Users table.
Use this:
$DB->query(SELECT * FROM users WHERE id IN(select friend_id FROM
friends WHERE user_id != {$my_id}))
Will work. :)
Not knowing the exact structure of your db makes your question a bit trick however going by the idea that someone is said to be your friend when he is your friend or you are his friend, you have to select those who you didn't add as friend and they as well didn't add you.
A query like this should help you.
"SELECT * FROM users WHERE users.id NOT IN (select * from friends where user_id != '{$your_id}' AND friend_id != '{$your_id}')"
I have a members table in which every site member is the unique id.
eg
id firstname secondname emailaddress country city gender
the second table is a friends table with the following structure
id meid friendid date
what query would i use to get friend suggestions of a particular user based on mutual friends and sorted accordingly. before i was using php to loop thru and collect mutual friends but as the site grew, php started misbehaving and running out of memory.
This is the function i was using
//-----------------------------------------------
function getFriendSuggestions($id)
{
$friendids=getFriendIdArray($id); //returns list of your friends
$networkids=getNetworkIdArray($id);//returns list of all members in your network(friends and their friends)
$diff=array_merge(array(),array_diff($networkids,$friendids));
$diff_mutual=array();
$diff_mutual_total=array();
for ($n=0;$n<count($diff);$n++)
{
$ff=getFriendIdArray($diff[$n]);
$mf=array_merge(array(),array_intersect($ff,$friendids));
$diff_mutual[]=$mf;
$diff_mutual_total[]=count($mf);
}
$diff=array_merge(array(),$diff);
$diff_mutual=array_merge(array(),$diff_mutual);
$diff_mutual_total=array_merge(array(),$diff_mutual_total);
$w=$diff_mutual_total;
arsort($w);
$d=array();
$dm=array();
foreach ($w as $key => $value)
{
$d[]=$diff[$key];
$dm[]=$diff_mutual[$key];
}
$cv=array($d,$dm);
return $cv;
}
We say that B is possibly-friend of A if there is a large number of entries of the kind
(B, someguy) (someguy, A)
in the database, and there is no (B, A) entry.
We know the ID of user A and let it be AID. Then we can do:
SELECT b.meid, COUNT(b.meid) AS incommon
FROM friends AS b
JOIN friends AS a ON (b.friendid = a.meid AND a.friendid = AID)
GROUP BY b.meid ORDER BY incommon DESC;
This will tell us all "possible friends" of A, including those that are
already friends of A. Then we have to exclude them:
SELECT maybe.meid, maybe.incommon FROM
( SELECT b.meid, COUNT(b.meid) AS incommon
FROM friends AS b
JOIN friends AS a ON (b.friendid = a.meid AND a.friendid = AID)
GROUP BY b.meid ORDER BY incommon DESC ) AS maybe
LEFT JOIN friends AS already ON (maybe.friendid = already.meid AND already.friendid = AID) WHERE already.friendid IS NULL;
Then we need to populate the rest of the fields:
SELECT members.firstname, members.secondname, maybe.incommon FROM
( SELECT b.meid, COUNT(b.meid) AS incommon
FROM friends AS b
JOIN friends AS a ON (b.friendid = a.meid AND a.friendid = AID)
GROUP BY b.meid ORDER BY incommon DESC ) AS maybe
LEFT JOIN friends AS already ON (maybe.friendid = already.meid AND already.friendid = AID)
JOIN members ON (members.id = maybe.meid)
WHERE already.friendid IS NULL;
This will return friend suggestions for AID, including how many people in common it has for every choice (e.g. "John Doe (15 friends in common)", etc.).
You want "friends of my friends, but who are not also my friends".
SELECT
me.id AS member_id,
their_friends.friendid AS suggested_friend_id,
COUNT(*) AS friends_in_common
FROM
members AS me
INNER JOIN
friends_map AS my_friends
ON my_friends.meid = me.id
INNER JOIN
friends_map AS their_friends
ON their_friends.meid = my_friends.friendid
LEFT JOIN
friends_map AS friends_with_me
ON friends_with_me.meid = their_friends.friendid
AND friends_with_me.friendid = me.id
WHERE
friends_with_me.meid IS NULL
GROUP BY
me.id,
their_friends.friendid
I have a query that retrieves the users that are online, and a users friends. Now I want to know the best way to combine the two so I can get the results of the users friends that are online.
Friends query:
SELECT
CASE WHEN userID=$session
THEN userID2
ELSE userID
END AS friendID
FROM friends
WHERE userID=$id OR userID2=$session
LIMIT 18
users online:
SELECT *
FROM usersActivity
WHERE setActivity!=3
AND userID!=$session
usersActivity.userID needs to match friendID
Query should be:
SELECT users.name
FROM usersActivity
INNER JOIN friends ON
(usersActivity.userID = usersActivity.userID AND usersActivity.userID2 = $session) OR
(usersActivity.userID2 = usersActivity.userID AND usersActivity.userID = $session)
INNER JOIN users ON
(usersActivity.userID = users.userID) OR
(usersActivity.userID2 = users.userID)
WHERE usersActivity.setActivity!=3
AND usersActivity.userID!=$session
AND users.userID != $session
GROUP BY users.id
You may use COUNT(user.id) if you want only count of users. Or select all names (store them for later use in listing) and use only mysql_num_rows() for getting actual number of friends online
I think I understand what your after:
SELECT userID FROM usersActivity
WHERE setActivity !=3
AND userID IN(
(SELECT userID FROM friends WHERE userID2=$id)
);
This assumes you have double rows for your friend linking table and $id is the current logged in user.
userID userID2
1 2
2 1
Using subqueries in your where statement should consolidate this. Not sure if this will be faster or not, depends on how you are doing things so profile it. You can join on your users table to get the friends name information and what other info you need.