I'm trying to show relation between two users. I want to insert only one row to Relations table (see structure below). But my script is showing that user B is friend of himself - that's not right.
This is a structure of my database (with examples):
Users
id|email|password|name|pic_url|friend_count
1 |a#.. |aaaaaaaa|A |http...|1
2 |b#...|bbbbbbbb|B |http...|0
Relations
id|user_id|friend_id|status(0 and 1)
1 |1 |2 |1(if accepted)
What am I doing wrong? Here's my query:
SELECT Relations.friend_id, Users.name,Users.email,Users.pic_url FROM Relations
INNER JOIN Users
ON Relations.friend_id = Users.id
WHERE Relations.user_id = $user_id
OR Relations.friend_id = $user_id
AND Relations.status = 1
I recommend to insert two rows into Relations table.
id|user_id|friend_id|status(0 and 1)
1 |1 |2 |1(if accepted)
2 |2 |1 |1(if accepted)
For example, user A send friend request to B. Until B accept this request, the status of both rows would be 0.
Query for accepting: (user B)
UPDATE Relations SET status=1 WHERE (user_id=$user_id AND friend_id=$friend_id) OR (user_id=$friend_id AND friend_id=$user_id)
Query for selecting:
SELECT Relations.friend_id, Users.name, Users.email, Users.pic_url FROM Relations
INNER JOIN Users
ON Relations.friend_id = Users.id
WHERE Relations.user_id = $user_id
AND Relations.status = 1
Update: If you really want to insert only one row, you would need to execute two queries - the one for the friends user B added and another one for the friends that has added User B to their friend list.
SELECT Relations.friend_id, Users.name, Users.email, Users.pic_url FROM Relations
INNER JOIN Users
ON Relations.friend_id = Users.id
WHERE Relations.user_id = $user_id
AND Relations.status = 1
SELECT Relations.user_id, Users.name, Users.email, Users.pic_url FROM Relations
INNER JOIN Users
ON Relations.user_id = Users.id
WHERE Relations.friend_id = $user_id
AND Relations.status = 1
Your problem is that you're selecting friend_id which means that if you execute your query as user B, the friend_id would be 2 - user B. (see your table example)
You should take a look to this question for more information about performance.
Related
I am having difficulty getting the results from 1 query and making them display in alpha order when the results are numerical.
TABLE1: "users" ROWS: user_id, username
TABLE2: "friends" ROWS: user_id, friend_id, confirmed
When YOU friend someone or they friend you, and you confirm, you create a "confirmed state" of 1.
With that in mind:
If I make the following query:
SELECT user_id
FROM friends
WHERE friend_id = 4
AND confirmed = 1
UNION
SELECT friend_id
FROM friends
WHERE user_id = 4
AND confirmed=1
I get a list of all my friends id's. I am user '4'.
What I would like to do now is take this result and look up their usernames from "users" and put them into Alphabetical order to compile a "Friends List"
I've tried all combinations of JOIN etc, but just cant get my head round it.
Please help, Any ideas?
SELECT u.*
FROM user u
JOIN
( SELECT user_id
FROM friends
WHERE friend_id = 4
AND confirmed = 1
UNION
SELECT friend_id
FROM friends
WHERE user_id = 4
AND confirmed=1
) x
ON x.user_id = u.user_id
ORDER
BY something
Update: I figured it out. See my answer below.
I'm trying to write some logic at the application level to identify the friends (mutual followers)in the table below. My query has returned the data in a format similar to the table below (borrowed from this question, but I don't need a query, that part's done):
A B
1 2 // mutual followers, so "friends"
2 1 // mutual followers, so "friends"
1 3 // user 1 is following 3
1 4 // user 1 is following 4
So how can I write some logic which shows the users where A = B and B = A, but in different rows? Using PHP/codeigniter.
In response to a request, here's the SQL tables and query:
Users table - uid, fname, lname
Followers table - user_id, follow_id
Select users.uid, users.fname, users.lname, u.uid, u.fname, u.lname
FROM users
INNER JOIN follows f on (f.user_id=users.uid)
INNER JOIN users u on (u.uid=f.follow_id)
I think you want something like this:
$results = array(array(1,2),array(2,1),array(1,3),array(1,4));
$mutual_users = array_filter($results,function($elem)use($results){
if(in_array(array_reverse($elem),$results)){
return true;
}
});
print_r($mutual_users);
Okay, I figured it out. I needed a second INNER JOIN for the followers table. I added the code below to my SQL query, and it worked.
INNER JOIN followers f2 ON u.id = f2.user_id AND users.id = f2.follow_id
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.
I have a users like this:
id username
1 user1
2 user2
3 user3
and a msgs like this:
t_id sent_by id msg
1 2 1 whatever
2 3 1 is
3 2 1 here
Where users.id is a primary key and msgs.id is a foreign key. In the msgs table, id is the destination of the message sent by sent_by.
I want to select and display the username of sent_by as long as the logged in user (via sessions) is the msgs.id.
To clarify things, here is the pseudocode of what I wanted to do:
Users has logged in. Store its userid to session.
Display the distinct usernames of who sent me (the logged in user) the messages. In the example above, the display will be: user2, user3 if I have a user id of 1.
I was thinking of using join but ended up doing 2 queries for the sent_by and ids. It seems not an efficient query.
What should I do?
This is a straightforward JOIN since you only wish to return usernames of the sent_by ids.
$sql = "SELECT DISTINCT
users.username
msgs.sent_by
FROM users JOIN msgs ON users.id = msgs.sent_by
WHERE id = {$_SESSION['my_userid']}";
SELECT DISTINCT u.username, m.sent_by
FROM msgs m
INNER JOIN users u ON u.id = m.sent_by
WHERE m.id = {$_SESSION['userid']}
ORDER BY m.t_id DESC
The following is what I got right now, which does not work properly because it checks one row for two different values.
SELECT users.*
FROM users INNER JOIN roles_users ru ON users.id = ru.user_id
WHERE ru.role_id = 1 AND ru.role_id = 2
I would like to select all users that have two rows in roles_users. The one rows role_id should have one and the second should have role_id two.
So select all users that have two rows in the roles_users where one of them has role_id = 1 and the other has role_id = 2.
The above query selects all users that have one row in roles_users that has first one and then two, that's why I get no results and it does not work. So how can I do this right?
SELECT users.id
FROM users INNER JOIN roles_users ON users.id = roles_users.user_id
WHERE roles_users.role_id IN (1, 2)
GROUP BY users.id
HAVING COUNT(*) = 2
Why not just join in on roles_users twice? Ala:
SELECT users.* FROM users
INNER JOIN roles_users ru1 ON users.id = ru1.role_id AND ru1.role_id = 1
INNER JOIN roles_users ru2 ON users.id = ru2.role_id AND ru2.role_id = 2
You need to get a (distinct) list of the users having the required roles. Try this instead:
SELECT users.{column_list}
FROM users as a
JOIN (SELECT user_id
FROM roles_users
WHERE role_id IN (1, 2)
GROUP BY user_id
HAVING COUNT(DISTINCT role_id) = 2) required_role
ON required_role.user_id = users.id