could someone help me, I need to get users who are not my friends
I have the following tables
users
id
user
1
Name1
2
name2
and the table friends:
id
id_user
id_friends
1
2
3
2
5
4
I try something like that, but in some queries it returns the ones that I already have added
Select u.*
from users u left join friends f
on f.id_user = 2
and f.id_friends = u.id
where u.id <> 2
and f.id_friend is null
One way is using NOT EXISTS to return all users not already "friended". That includes users not already in the friends table.
SELECT u.*
FROM users u
WHERE u.id <> 2
AND NOT EXISTS (
SELECT NULL
FROM friends f
WHERE ( f.id_friend = u.id AND f.id_user = 2 )
OR ( f.id_friend = 2 AND f.id_user = u.id )
)
Results:
id | user
-: | :----
1 | Name1
db<>fiddle here
Related
I am having trouble listing my friend list along with all users
I used this statement to list all the friend list of user_id 1 :
SELECT users.user_id, username, full_name, avatar, user_type, last_active FROM users JOIN user_active ua on users.user_id = ua.user_id WHERE users.user_id IN( (SELECT user_id1 FROM friends WHERE user_id2 = 1) UNION (SELECT user_id2 FROM friends WHERE user_id1 = 1)) AND users.status = 1;
I can also use this statement to find friend list of user_id 1 along with all people but there is now way to identify who is my or who is not in my friend list:
SELECT users.user_id, username, full_name, avatar, user_type, last_active FROM users JOIN user_active ua on users.user_id = ua.user_id WHERE users.user_id IN( (SELECT user_id1 FROM friends WHERE user_id2 = 1) UNION (SELECT user_id2 FROM friends WHERE user_id1 = 1)) OR users.user_id != 1 AND users.status = 1;
details of friends table:
+------------+---------------+----+---+-----------------+-----------------+
|Field |Type |Null|Key|Default |Extra |
+------------+---------------+----+---+-----------------+-----------------+
|f_request_id|bigint unsigned|NO |PRI|NULL |auto_increment |
|user_id1 |bigint |NO | |NULL | |
|user_id2 |bigint |NO | |NULL | |
|created_at |timestamp |NO | |CURRENT_TIMESTAMP|DEFAULT_GENERATED|
+------------+---------------+----+---+-----------------+-----------------+
if you guys can help me add an extra column on the result like is_friend with value containing 0 or 1, 0 for nor friend 1 for friend, I will be very grateful.
Thanks in advance
Use a LEFT join of users to friends:
SELECT u.*,
COALESCE(NULLIF(f.user_id1, ?), f.user_id2) IS NOT NULL is_friend
FROM users u LEFT JOIN friends f
ON u.user_id IN (f.user_id1, f.user_id2) AND ? IN (f.user_id1, f.user_id2)
WHERE u.user_id <> ? AND u.status = 1;
Change the 3 occurrences of the placeholder ? to the id of the user you want to get the results.
If you get duplicate results because the table friends may contain 2 rows for the same friendship (like (1,2) and (2,1)) then use SELECT DISTINCT u.* .....
Or, use EXISTS:
SELECT u.*,
EXISTS (
SELECT *
FROM friends f
WHERE u.user_id IN (f.user_id1, f.user_id2) AND ? IN (f.user_id1, f.user_id2)
) is_friend
FROM users u
WHERE u.user_id <> ? AND u.status = 1;
See a simplified demo.
I am looking to show a mutual friends function but my user friends list is stored on another table.
I want to know if it's possible to use the data of each row as a clause for join B
SELECT * FROM ( SELECT * FROM `users`) a
CROSS JOIN (SELECT COUNT(*) AS MUTUAL_FRIENDS
FROM `user_friends` WHERE `friend_to` = `a`.`userid`) b
ORDER BY `b`.`MUTUAL_FRIENDS` ASC
What I am looking to do is use the userid from users table as a clause for the join with:
`friend_to` = `a`.`userid`
Expected results:
+--------=+---------+-----------+--------------+
| userid | Username |Photo_URL |MUTUAL_FRIENDS|
+---------+---------+-----------+--------------+
1 Somename1 /image1.png 3
4 Somename4 /image4.png 2
2 Somename2 /image2.png 1
3 Somename3 /image3.png 0
5 Somename5 /image5.png 0
Friends table:
+--------=+---------+-----------+
| friend_id | userid |friend_to |
+---------+---------+-----------+
1 1 2
2 2 1
3 1 3
4 3 1
5 1 4
6 4 1
Users Table
+--------=+---------+-----------+
| userid | Username |Photo_URL |
+---------+---------+-----------+
1 Somename1 /image1.png
2 Somename2 /image2.png
3 Somename3 /image3.png
4 Somename4 /image4.png
5 Somename5 /image5.png
Or am I doing this totaly wrong?
Here is one approach.
With CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a
CROSS JOIN Friends b
WHERE a.userid = b.friend_to and a.friend_to = b.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
Without CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a, Friends b
WHERE a.friend_to = b.userid and b.friend_to = a.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
I will try to explain little by little and please correct me if there is error.
The condition a.friend_to = b.userid and b.friend_to = a.userid is
used to select only mutual friend. Then if a user has this kind of
"mutual connection," the corresponding userid will appear once.
Get the count along with the userid.
Left join the userid and count table.
Result
userid Username Photo_URL MUTUAL_FRIENDS
1 Somename1 /image1.png 3
2 Somename2 /image2.png 1
3 Somename3 /image3.png 1
4 Somename4 /image4.png 1
5 Somename5 /image5.png 0
Given the data, user1 is mutual friend of user2, user3 and user4. User2 is only mutual friend of user 1 and so as user 3 and user4.
With CROSS JOIN SQL Fiddle
Without CROSS JOIN SQL Fiddle
I have 3 tables:
tbl_user stores all user details (user_id,name,address)
user_id name address
1 a (shop) home
2 b (shop) bakerstreet
3 c (staff) wallstreet
4 d (staff) georgia
5 e (staff) sydney
tbl_user_group stores user type (user_id,user_type : 1=shop_owner,2=staff)
user_id user_type
1 1
2 1
3 2
4 2
5 2
tbl_user_association holds the shop_owner and staff relation (shop_owner_id, staff_id)
shop_owner_id staff_id
1 3
1 4
1 5
2 3
2 4
desired result
i want to display the list of staffs and the respective shops that they are associated with as follows:
user_id staff_name shop_owner
3 c a,b
4 d a,b
5 e a
I tried using the group_concat as mentioned here. The query is as follows:
SELECT
u.id AS user_id,
u.name AS staff_name,
(SELECT GROUP_CONCAT(u.name separator ',') FROM tbl_user u WHERE u.id = ua.shop_owner_id) AS
shop_owner
FROM tbl_user u
JOIN tbl_user_group ug ON u.id = ug.user_id
LEFT JOIN tbl_user_association ua ON u.id = ua.staff_id
WHERE ug.user_type = 2
GROUP BY u.id
But it returns single row of staffs as below. where have i gone wrong?
user_id staff_name shop_owner
3 c a
4 d a
5 e a
This is how I'd do it:
SELECT
u.user_id,
u.name,
GROUP_CONCAT( so.name )
FROM
tbl_user_group ug
INNER JOIN tbl_user u
ON ( ug.user_id = u.user_id )
INNER JOIN tbl_user_association ua
ON ( ua.staff_id = u.user_id )
INNER JOIN tbl_user so -- here join again the user table to get shop owners names
ON ( ua.shop_owner_id = so.user_id )
WHERE
ug.user_type = 2
GROUP BY
u.user_id;
I have the following table structure with data
TABLE: USER
USER ID | USER NAME
1 | Joe
2 | Mary
TABLE : USER GROUP
USER ID | GROUP ID
1 | 1
1 | 2
TABLE : GROUP
GROUP ID | GROUP NAME
1 | Company 1
2 | Company 2
TABLE : ROLE
ROLE ID | ROLE NAME
1 | Administrator
2 | Users
TABLE : USER ROLE
USER ID | ROLE ID
1 | 1
2 | 1
As you can see user #2 does not belong to any group. Roles & Groups are optional forcing me to left joint but when I run a query as below
`SELECT a.user_id,
a.user_name
GROUP_CONCAT(r.role_name) AS role_names,
GROUP_CONCAT(g.group_name) AS group_names
FROM user a
LEFT JOIN role_map m ON a.user_id = m.user_id
INNER JOIN role r ON m.role_id = r.role_id
LEFT JOIN user_group s ON a.user_id = s.user_id
INNER JOIN group g ON s.group_id = g.group_id
GROUP BY a.user_id`
I get a cartesian product in the role_names column - the result looks like this
Joe | Administrators, Administrators | Company 1, Company 2
What am I doing wrong?
The easiest way to solve this is by using DISTINCT in your GROUP_CONCAT (SQL Fiddle). Also, you will need to add GROUP BY a.user_id in order to group per user:
SELECT a.user_id,
a.user_name,
GROUP_CONCAT(DISTINCT r.role_name) AS role_names,
GROUP_CONCAT(DISTINCT g.group_name) AS group_names
FROM `user` a
LEFT JOIN `user_role` m ON a.user_id = m.user_id
LEFT JOIN `role` r ON m.role_id = r.role_id
LEFT JOIN `user_group` s ON a.user_id = s.user_id
LEFT JOIN `group` g ON s.group_id = g.group_id
GROUP BY a.user_id;
I have two tables inside a database. One stores unique userNames and a unique id and the other stores which users from the previous table are "friends": ex:
table users:
id | username
---------------
100 | aaa
200 | bbb
300 | ccc
table friends:
id | user | friend
-------------------
1 | 100 | 200
2 | 300 | 100
3 | 300 | 200
Like in the above example, user 100 is friends with 300 and also 200.
I'd like to display a list containing all of users 100 friends. Keep in mind he can appear in the "friends" table on both columns (user and friend). Can't figure out how the query should look like. Everything i try, it duplicates rows and whatnot.
I know it's trivial, but i'm new at this.
This will work with no duplicate
SELECT distinct id FROM(
SELECT friend as id FROM friends
WHERE user = 100
UNION ALL
SELECT user as id FROM friends
WHERE friend = 100) ;
Try this:
Select distinct u.id, u.username
from Users u
inner join Friends f on u.id = f.id
where f.friend = 100
UNION ALL
Select distinct u.id, u.username
from Users u
inner join Friends f on u.id = f.id
where f.user = 100
Or:
Select distinct u.id, u.username
from Users u
inner join Friends f on u.id = f.id
where f.user = 100 or f.friend = 100
try below :
Select distinct u.id, u.username
from Users as u
left join Friends as f on (u.id = f.user or u.id = f.friend)
where u.id=100