SQL Statement that orders selected IDs first with condition - mysql

I have the following tables:
team_members
userid
teamid
users
uid
name_f
name_l
friends
friend_id
friend_one
friend_two
I use the following statement to select uid and profile_pic of the users that belong to a certain team.
SELECT DISTINCT u.uid, u.profile_pic
FROM friends f, users u, team_members m
WHERE m.teamid =$team_var
AND u.uid = m.userid
I also have to run the following to select the uid and profile_pic of the users who are friends with the logged-in user and belong to a certain team.
SELECT DISTINCT u.uid, u.profile_pic
FROM friends f, users u, team_members m
WHERE m.teamid =$team_var
AND u.uid = m.userid
AND m.userid = f.friend_two
AND f.friend_one =$session_id
I'm looking for a way to join these two and instead of running 2 queries, run one single query that can order and list the users who are friends with the logged-in user at the top. So let's say that a certain team has 30 users and 5 of those users are friends with the logged-in user, I would like to have the first 5 listed in the while loop following the statement to be those of the friends with the rest of the 25 randomly shown.
Thanks for your time.

This can easily be solved with an outer join. You will probably not be able to use an outer join without the explicit join syntax. Here:
SELECT
u.uid,
u.profile_pic,
(friend_id IS NOT NULL) AS is_friend
FROM team_members m
INNER JOIN users u ON m.userid = u.uid
LEFT JOIN friends f ON m.userid = f.friend_two AND f.friend_one = $session_id
WHERE m.teamid = $team_var
ORDER BY
is_friend DESC,
m.userid
The first two tables are joined using an inner join, so only the members of a specific team are returned (because we are filtering on teamid).
The friends table is outer-joined to the result of the previous join. More specifically, we a joining the subset of friends where friend_one is the current user. All rows from the previous result set are returned, but also rows from the friends's subset are returned where matched. Where not matched, the friends columns are filled with NULLs.
Using the NULL (or rather NOT NULL) test, we can see which team member is a friend and which isn't. The result of the test is returned as a column and also used as a sorting criterion for the output rows.

You would need to create another column which has a value of "friend" or not "friend". You would then use that column as an ORDER BY. The column you create could be a subquery to determine if the other user is a friend or not. The following code is wrong because you need to hook the data from the outer query into the subquery, but it should look something like:
SELECT DISTINCT u.uid, u.profile_pic,
EXISTS (SELECT DISTINCT u.uid, u.profile_pic
FROM friends f, users u, team_members m
WHERE m.teamid =$team_var
AND u.uid = m.userid
AND m.userid = f.friend_two
AND f.friend_one =$session_id
) AS myColumn
FROM friends f, users u, team_members m
WHERE m.teamid =$team_var
AND u.uid = m.userid
ORDER BY myColumn

I might suggest this:
select u.uid, u.profile_pic
from team_members t
join team_members m on t.teamid = m.teamid
join users u on m.userid = u.uid
left join friends f on t.userid = f.friend_one and m.userid = f.friend_two
where m.userid != t.userid
and t.userid = $session_id -- This line can be removed to view all (test)
order by
--t.teamid, t.userid, -- This line can be added to order all (test)
(case when f.friend_id is null then 1 else 0 end case),
f.friend_id, m.userid
I'm using explicit join syntax (which is normally recommended these days) and using that case statement in the order by to get friends to the top. I don't have MySQL running here to test it, but the syntax should be pretty standard (I'm running something very similar on SQL Server).

Related

ORDER BY column FROM another table

I want to order user's friends by last_act with them. But information about users is in table users and last_act in table friends.
I tried this but it didn't work:
SELECT m.*
FROM users AS m
WHERE m.username = '$username'
JOIN friends AS p
ORDER BY p.last_act DESC
You should have a foreign key on friends table for user.
For eg say it userid.
Then above query will be:
SELECT m.*
FROM users AS m
JOIN friends AS p ON p.userid = m.id
WHERE m.username = '$username'
ORDER BY p.last_act DESC
Your question is too vague, we don't know the structure of tables and we don't see error message neither...
but is see there an order issue, it must go as SELECT, FROM, JOIN, WHERE. And you need use ON to map relation in JOIN.
example
SELECT * FROM table1 JOIN table2 ON table1.id = table2.foreign_id
SELECT m.*, f.*
FROM users AS m
JOIN friends AS p
ON m.id = p.user_id
LEFT JOIN users AS f
ON p.friend_id = f.id
WHERE m.username = '$username'
ORDER BY p.last_act DESC

MySQL complex select query filtering from third table

I have three tables.
users, friends and communityusers tables.
I am trying to build a facebook like group system. User will try to search his/her friends from friend lists to add them to the group.
So here I am trying to remove those friends who are already added in the group. Here group users table is communityusers..
This is the structure of my communityusers table.
id | community_id | user_id
I am not being able to use this table with my current query.
SELECT f.id, u.id as user_id, u.userName, u.firstName, u.lastName, u.profilePic from friends f, users u
WHERE CASE
WHEN f.following_id=1
THEN f.follower_id = u.id
WHEN f.follower_id=1
THEN f.following_id = u.id
END
AND
f.status= 2
AND
(
u.firstName LIKE 's%' OR u.lastName LIKE 's%'
)
This query returns the friends lists of user id 1 now I want exclude users filtering from the communityusers table.
user_id from this query shouldn't be present in the communityusers table. How can I filter this from communityusers or third table?
Please let me know if question is not clear.
Any suggestion, idea and help would be highly appreciated.
Thank you so much.
Edit
After running the query I get
My communityusers table
See user_id = 2 is also selected from the above query. I want to remove the user_id = 2 from the result since it exists in the communityusers table.
I am trying to create a Fiddle but for some reason it's not working for me.
Thank you again.
#sadek
Simply use not in, in where condition
SELECT f.id, u.id as user_id, u.userName, u.firstName, u.lastName, u.profilePic
from friends f inner join users u on
CASE WHEN f.following_id=1 THEN f.follower_id = u.id WHEN f.follower_id=1 THEN f.following_id = u.id
END AND f.status= 2
where u.id not in (select distinct user_id from communityusers) and (u.firstName LIKE 's%' OR u.lastName LIKE 's%')
Try using left join with communityuser table by given condition cu.user_id is null - this will give you those users which are not in communituuser table
select a.* from
(SELECT f.id, u.id as user_id, u.userName, u.firstName, u.lastName, u.profilePic from friends f inner join users u
on CASE WHEN f.following_id=1 THEN f.follower_id = u.id WHEN f.follower_id=1 THEN f.following_id = u.id
END AND f.status= 2 where u.firstName LIKE 's%' OR u.lastName LIKE 's%')a
left join (select * from communityuser where community_id<>4) cu on a.user_id=cu.user_id
where cu.user_id is null

'friends of friends' SQL query

This question is related to previous one. You can check my first post here
I'm trying to pull data from a user table and I need 'friends of friends', those who are two steps away from the chosen user but not directly connected to the chosen user
I tried with this query:
select
u.*
from user u
inner join friend f
on u.user_id = f.friend_id
inner join friend ff
on f.user_id = ff.friend_id
where ff.user_id = {$user_id} AND u.user_id <> {$user_id};
I didn't know how to pull users who are not directly connected to the chosen user. I get all friends of friends of the current user, but I also get direct friends of the current user.
You just need to exclude the ones who are direct friends as well as being friends-of-friends. I've rearranged the table aliases so it's a bit clearer (to me, anyway) what's being retrieved:
SELECT
u.*
FROM
user u
INNER JOIN friend ff ON u.user_id = ff.friend_id
INNER JOIN friend f ON ff.user_id = f.friend_id
WHERE
f.user_id = {$user_id}
AND ff.friend_id NOT IN
(SELECT friend_id FROM friend WHERE user_id = {$user_id})
It also removes the need to exclude the user ID being queried.
You are on the right track. You need to add a where condition that excludes those who are directly related:
select u.*
from user u
inner join friend f on u.user_id = f.friend_id
inner join friend ff on f.user_id = ff.friend_id
where ff.user_id = {$user_id} AND u.user_id <> {$user_id};
AND not exists
(select f2.friend_id
from friend f2
where f2.friend_id = ff.friend_id
and u.user_id = f2.user_id)
The extra not exists clause that I added to your query verifies that the second degree friend is also not a first degree friend.
I'd use a non-correlated subquery, which retrieves the ids of the direct friendships of {$user_id}, and exclude these users from the final result:
select u.*
from user u
inner join friend f on u.user_id = f.friend_id
inner join friend ff on f.user_id = ff.friend_id
where ff.user_id = {$user_id} AND u.user_id <> {$user_id}
AND u.user_id not in (
select directFriend.friend_id
from friend directFriend
where directFriend.user_id = {$user_id})

mysql join 2 tables with on condition , keep some values

I have 2 tables.
users(id,username) and links(id,usernameORid).
Example of rows: users{ [1,test] , [2,stack] } and links{ [1,overflow] , [2, 1] }
So, table links may contain username or id from table users. As you can see in the example,
usernameORid from links may not contain the id or username from users.
I hope you understood my example.
Now, i have this query:
SELECT l.usernameORid, u.username, u.id
FROM links l
LEFT JOIN users u
ON l.usernameORid= u.id
LEFT JOIN user_roles ur
ON ur.userID = u.id
WHERE ur.roleID < 4
group by u.id
But this query does not return rows from links if usernameORid is not an actual username or id from users.
In the previous example, will not return row [1,overflow]. I want that row too.
How can i achieve that?
EDIT: The problem is partialy related to
LEFT JOIN user_roles ur
ON ur.userID = u.id
WHERE ur.roleID < 4
but still, how can i achieve that?
user_roles ( id,userID,roleID)
Change your final WHERE condition to:
WHERE ur.roleID < 4 OR u.id IS NULL
This will allow it to return rows that didn't have a match in users. Normally a LEFT JOIN does that by itself, but since you're doing an additional join on that table, the WHERE clause is filtering those non-matching rows out because they don't have a roleID.
You can use an OR statement in your join between links and users. This will allow you to pick up users records where the link.usernameORid is equal to either the users.id or the users.username
SELECT l.usernameORid,
u.username,
u.id
FROM links l
LEFT JOIN users u ON
l.usernameORid = u.id OR
lusernameORid = u.username
LEFT JOIN user_roles ur
ON ur.userID = u.id
WHERE ur.roleID < 4
GROUP BY u.id
This will still cause records to drop if the found users->user_roles.roleID is less than 4. If you wanted to have link records maintained regardless of whether of a user was found by username or ID then you would need to subquery the users and user_roles table joins and apply your WHERE statement there instead. This query is below:
SELECT
l.usernameORid,
u.username,
u.id
FROM links l
LEFT JOIN
(
SELECT
users.username,
users.idusers
FROM
users
LEFT JOIN user_roles ON
user_roles.userID = users.id
WHERE
user_roles.roleID < 4
) u ON
l.usernameORid= u.id OR
l.usernameORid = u.username
group by u.id
Furthermore, if you wish the 2nd or 3rd column of your return to hold the value that is in l.usernameORid when the users table lacks a match... if your users.id is always numeric you could do some trickery with a CASE statement:
SELECT
l.usernameORid,
Coalesce(u.username, CASE WHEN .lusernameORid REGEXP '^[0-9]+$' THEN NULL ELSE l.usernameORid END) as username,
Coalesce(u.username, CASE WHEN .lusernameORid REGEXP '^[0-9]+$' THEN l.usernameORid ELSE NULL END) as userid
FROM links l
LEFT JOIN
(
SELECT
users.username,
users.idusers
FROM
users
LEFT JOIN user_roles ON
user_roles.userID = users.id
WHERE
user_roles.roleID < 4
) u ON
l.usernameORid= u.id OR
l.usernameORid = u.username
group by u.id
Keep in mind though, that if the users table doesn't have a match for the links.usernameORid then only the username OR the id could be determined, so you will have a NULL in one of the two fields.

Select Two Values Based Off Same Column

I am trying to select two usernames in one row of a query one would be called 'username' and the second one say 'username2'. This is the code I have atm. The users table uses a primary key of user_id.
SELECT
r.report_id,
r.poster_id,
r.reporter_id,
u.username,
(2nd username)
FROM reports r,
users u
WHERE r.report_id = :report_id
AND r.reporter_id = u.user_id
AND r.poster_id = u.user_id
you need to join the table user twice
SELECT
r.report_id,
r.poster_id,
r.reporter_id,
u.username AS ReporterName,
b.userName as PosterName
FROM
reports r
INNER JOIN users u
ON r.reporter_id=u.user_id
INNER JOIN users b
ON r.poster_id=b.user_id
WHERE
r.report_id=:report_id
Here is the code for MySQL
SELECT
r.report_id,
r.poster_id,
r.reporter_id,
u.username,
u.username username2,
FROM reports r,
users u
WHERE r.report_id = :report_id
AND r.reporter_id = u.user_id
AND r.poster_id = u.user_id