SQL select for friendships table in cometchat - mysql

Im beginner in sql soo i have big problem with this "big" select for friends table in cometchat. Can somebody write it for me.
Cometchat is configured for friends table :
friends
toid fromid
id 2 1
id 1 2
and sql select for it:
$sql = ("select DISTINCT ".TABLE_PREFIX.DB_USERTABLE.".".DB_USERTABLE_USERID." userid, ".TABLE_PREFIX.DB_USERTABLE.".".DB_USERTABLE_NAME." username,
".TABLE_PREFIX.DB_USERTABLE.".".DB_USERTABLE_LASTACTIVITY." lastactivity,
".DB_AVATARFIELD." avatar, ".TABLE_PREFIX.DB_USERTABLE.".".DB_USERTABLE_USERID." link,
cometchat_status.message, cometchat_status.status
from ".TABLE_PREFIX."friends join ".TABLE_PREFIX.DB_USERTABLE." on ".TABLE_PREFIX."friends.toid = ".TABLE_PREFIX.DB_USERTABLE.".".DB_USERTABLE_USERID." left join cometchat_status on ".TABLE_PREFIX.DB_USERTABLE.".".DB_USERTABLE_USERID." = cometchat_status.userid ".DB_AVATARTABLE."
where ".TABLE_PREFIX."friends.fromid = '".mysql_real_escape_string($userid)."' order by username asc");
return &sql;
My Rails app have friendships table :
friendships
user_id friend_id
id 1 2
id 2 1
When i just change order it does not work. I think that this is to hard for me right now. In rails i just check which friendship has a user_id of my profile and i show it friend_is as a friend.
THis is generated SQL for standard cometchat settings with friend table:
select DISTINCT users.id userid,
users.name username,
users.current_sign_in_at lastactivity,
users.id avatar,
users.id link,
cometchat_status.message,
cometchat_status.status
from friends
join users on friends.toid = users.id
left join cometchat_status on users.id = cometchat_status.userid
where friends.fromid = '10'
order by username asc
i try to change table from friends to my fiendships and toid (on friend_id) and formid( on user_id) and and vice versa but still it doesnt work and i do not get friends list.

Related

MySql query to check list of ids if they are friends with me?

So I have a list of ids(userId's) that was found using a sql command that I want to check with my friends table to see if they are indeed friends with myself, a userid I will provide with, and have a column that will represent if they are and also group them if they are my friend and not my friend.
Example:
List of userids:
1
2
3
Friends table:
-------
userId *the userid sending a friend request*
friendId *the userid receiving the friend request*
relationshipId *an unique id for the relationship*
initiated_by *the userid initiating the friend request*
status *whether or not the users are friends 'friends' or 'pending'*
sample friends table data
I tried creating a subquery that would first get the list of ids I want, and then tried to compare it with my friends table but couldn't quite put it together because the friends table is not bidirectional, meaning each row represents a relationship between 2 people with a status friends or pending
Use a CASE expression to get the friend of a person (i.e. pick either the userid or the friendid from the friends table).
As of MySQL 8 you can use a WITH clause to get this readable:
with friends_of_user_1 as
(
select case when userid = 1 then friendid else userid end as userid
from friends
where 1 in (userid, friendid)
and status = 'friends'
)
, friends_of_user_2 as
(
select case when userid = 2 then friendid else userid end as userid
from friends
where 2 in (userid, friendid)
and status = 'friends'
)
select
userid,
userid in (select userid from friends_of_user_2) as is_friend_of_user_2
from friends_of_user_1;
The same without WITH:
select
userid,
userid in
(
select case when userid = 2 then friendid else userid end as userid
from friends
where 2 in (userid, friendid)
and status = 'friends'
) as is_friend_of_user_2
from
(
select case when userid = 1 then friendid else userid end as userid
from friends
where 1 in (userid, friendid)
and status = 'friends'
) friends_of_user_1;
You can get all friends bidirectional, i.e. (a,b), (b,a), (a,c), (c,a), ... with a UNION query. If it is guaranteed that there exists no (b,a) in the table when there exists (a,b), then you can use UNION ALL, otherwise use UNION.
Then you can aggregate per user and see whether they are friends with user 1 and/or user 2:
with all_friends as
(
select userid as userid1, friendid as userid2 from friends status = 'friends'
union
select friendid as userid1, userid as userid2 from friends status = 'friends'
)
select
userid1,
sum(userid2 = 2) > 0 as is_friends_with_user_2
from all_friends
group by userid1
having sum(userid2 = 1) > 0 -- is friends with user 1
Use the alias of Friends a second time to get the reciprocal relationship
SELECT A.Name,...
FROM Users A
JOIN friends FA ON A.userID = FA.userID
LEFT JOIN friends FB ON FA.friedID = FB.userID
JOIN Users B on FB.userID = B.userID
...
So FA is the friends of A and FB is the friend relationship of B back to A.

Select only one row from a join based on foreign condition

The main idea
user hasMany roles (data is stored in the tables: users, roles, user_role)
i want to know if the user is admin OR client
this data will then be joined to a different result
What I'm doing
SELECT
`users`.`id`,
`users`.`name`,
`roles`.`display_name`
FROM `users`
JOIN role_user ON users.id = role_user.user_id
JOIN roles ON role_user.role_id = roles.id
Why it's wrong
Because this is the result I get
id Name Display name
1 admin Admin
1 admin Client
2 admin2 Admin
2 admin2 Client
3 client Client
7 test Admin
7 test Client
What I want
id Name Display name
1 admin Admin
2 admin2 Admin
3 client Client
7 test Admin
How I'm working to make this work
Using aggregates somehow
Using cases somehow
Joining with a subset of the data somehow
Thank you for your idea !
[Update] Here is an sqlFiddle describing the issue.
SELECT
`users`.`id`,
`users`.`name`,
`roles`.`display_name`
FROM `users`
LEFT JOIN role_user ON users.id = role_user.user_id
left JOIN roles ON role_user.role_id = roles.id
This solution should work fine for you:
select * from users
where users.id in (
select users.id FROM users
JOIN role_user ON (users.id = role_user.user_id)
JOIN roles ON (role_user.role_id = roles.id)
where roles.display_name like 'admin'
)
Union
select * from users
where users.id not in (
select users.id FROM users
JOIN role_user ON (users.id = role_user.user_id)
JOIN roles ON (role_user.role_id = roles.id)
where roles.display_name like 'admin'
);
Fiddle here: http://sqlfiddle.com/#!9/0fabba/42
I would recommend to create a view for the sub-query, but I couldn't do it on fiddle.
Example using a view:
Create or replace view admin_list as
select users.id FROM users
JOIN role_user ON (users.id = role_user.user_id)
JOIN roles ON (role_user.role_id = roles.id)
where roles.display_name like 'admin';
Then the query will be much compact:
select * from users
where users.id in (
select users.id FROM admin_list
)
Union
select * from users
where users.id not in (
select users.id FROM admin_list
);
My own solution was the following
create a view to get the user's role id (either admin or client)
join with the view
Specifically here is the view
CREATE VIEW vw_users_role_by_priority AS (
SELECT
role_user.user_id,
min(role_user.role_id) AS 'role_id'
FROM role_user
JOIN roles ON role_user.role_id = roles.id
GROUP BY role_user.user_id
);
And here is the final query
SELECT
`users`.`id`,
`roles`.display_name
FROM `users`
JOIN vw_users_role_by_priority ON vw_users_role_by_priority.user_id = users.id
JOIN roles ON roles.id = vw_users_role_by_priority.role_id
ORDER BY `users`.`name` ASC;
Try with this query :
SELECT users.`id`, users.`name`, MIN(roles.`display_name`)
FROM `users` users, `role_user` role_user, `roles` roles
WHERE users.id = role_user.user_id AND role_user.role_id = roles.id
GROUP BY users.`id`
In your query you join tables which give you all possible combinations of results. This query will select only the role_user/roles for each found userId.
EDIT : added "group by" to select only unique users and "min" to select its alphabetically lowest role (so "admin" get selected before "client")

A complex data not sure how to explain it

Hi I have a table called Users and a table called friends, friends table have two data types UserID and FriendID, (foreign key of both data types to primary key of the Users table),
I need to give an ID and find a list of that persons friends'name, I am not sure if I have designed the tables wrongly or I should rewrite the query.
my query is as following, (so far it just shows the details of first matched person)
SELECT Users.Name
FROM Users
WHERE Users.ID = SELECT Friends.UserID
FROM Friends,Users
WHERE Users.ID = (Select Users.ID
From Users
WHERE Users.Username = 'John')
Try this:
SELECT Users.Name FROM Users WHERE Users.ID IN -- Get names that belongt to ID's
(SELECT FriendID FROM Friends WHERE UserID = -- All ID's of the Friends of
(SELECT UserID FROM Users WHERE Name = 'John')) -- Johns ID
I've solved it by changing the first = to IN
is this you want to achieve ??
User
UserID (PK)
Name
Friend
FriendID (PK)
UserID (FK)
select User.Name from User u join Friend f on f.UserID = u.UserID where Name = 'John'

mysql query help to find mutual friends on social networking site

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)

MySQL users table: find rows that have the same email address

I have a users table in MySQL.
id | username | email
I would like to get the IDs of duplicated users based on the email address. So basically find the Ids of users where the email address can be found more than 1 times in the table.
I wrote something like this:
SELECT id
FROM users as users
WHERE (
SELECT count(id)
FROM users as users2
WHERE users.email = users2.email
) > 1
It works ok, but very slow, as the query doesn't seem to use the index. Any other ideas? Thanks!
The solution :
select u.id
from users as u
inner join
( SELECT email
FROM users
GROUP BY users.email
HAVING count(id) > 1
) as u2 on u2.email = u.email