find user2 friends + mutual count with user1 - php

mysql to find user2 Friends and get mutual_count with user1 ( with every user2 friend)
Table users
user_id | username
------------------
1 | user1
2 | user2
3 | user3
4 | user4
5 | user5
table friends
user_one_id | user_two_id
------------------------
1 | 2
1 | 4
2 | 3
2 | 4
3 | 1
5 | 2
Expected output //( user2 friends : check result user_id with user1 to get mutual count)
user_id | mutual_count
------------------------
1 | 2 // user1 and user1 mutual `users(user2,user3,user4)`
3 | 1 // user3 and user1 mutual users(user2)
4 | 1 // user4 and user1 mutual users(user2)
5 | 0 // user5 and user1 -> No mutual users
mysql statement
SELECT users.user_id,
(SELECT count(a.friendID) FROM
( SELECT user_two_id friendID FROM friends WHERE user_one_id = users.user_id
UNION
SELECT user_one_id friendID FROM friends WHERE user_two_id = users.user_id
) AS a
JOIN
( SELECT user_two_id friendID FROM friends WHERE user_one_id = 1
UNION
SELECT user_one_id friendID FROM friends WHERE user_two_id = 1
) AS b
ON a.friendID = b.friendID
) as mutual_count
FROM friends LEFT JOIN users
ON friends.user_one_id = users.user_id or friends.user_two_id = users.user_id
WHERE (friends.user_one_id = 2 OR friends.user_two_id = 2) AND users.user_id != 2
Error I get
Unknown column 'users.user_id' in 'where clause'
problem subquery to get mutual_count canot know users.user_id
any help appreciated

Your hunch to use a union between the friends table was on the right track. The issue here is that a relationship between friends is only recorded in one direction, but we really need to detect each relationship regardless of direction. The UNION trick allows each relationship to be counted properly.
In the query below, the base table is this union. We self join it, on the conditions that:
The first table's user_one_id is 2
The first table's user_two_id matches to the second table's user_one_id
The second table's user_two_id is not 2, which would just be a cycle back to where we started
Then, we just aggregate by the first table's user_two_id and count the number of distinct friends to get the result.
SELECT
t1.user_two_id AS user_id,
COUNT(DISTINCT t2.user_two_id) AS mutual_count
FROM
(
SELECT user_one_id, user_two_id
FROM friends
UNION ALL
SELECT user_two_id, user_one_id
FROM friends
) t1
LEFT JOIN
(
SELECT user_one_id, user_two_id
FROM friends
UNION ALL
SELECT user_two_id, user_one_id
FROM friends
) t2
ON t1.user_one_id = 2 AND
t1.user_two_id = t2.user_one_id AND
t2.user_two_id <> 2
WHERE
t1.user_two_id <> 2
GROUP BY
t1.user_two_id
ORDER BY
t1.user_two_id;
Demo

Related

How do i display friends of a user in mysql?

I am creating a friend list module.
I have 2 tables: users table and friends table. I want the program to display the friends of a user without displaying the user as one of his/her own friend.
My table looks like
Users table
---------- ---------- ---------
user_id | username | password
-------------------------------
1 | elexis | *******
-------------------------------
2 | rooney | *******
-------------------------------
3 | wayne | *******
-------------------------------
4 | June | *******
-------------------------------
Friends table
---------- ----------
user_id | friend_id
---------------------
1 | 3
-----------
2 | 1
-----------
2 | 4
-----------
1 | 2
Expected output of user_id 1 (who is elexis) should be
User_id friend_id Username
1 3 Wayne
2 1 Rooney
My code is thus:
SELECT t1.user_id,t1.friend_id, t2.username
FROM friends AS t1
LEFT JOIN users AS t2
ON (t1.user_id = t2.user_id)
OR (t1.friend_id = t2.user_id)
WHERE t1.user_id = 1
The output I'm getting is:
User_id Friend_id Username
1 5. Elexis
1 1 Elexis
What am I getting wrong?
Join Users to a query that contains distinct pairs of user with id = 1 and each pair:
SELECT f.*, u.username
FROM Users u
INNER JOIN (
SELECT user_id, friend_id FROM Friends WHERE user_id = 1
UNION
SELECT friend_id, user_id FROM Friends WHERE friend_id = 1
) f ON f.friend_id = u.user_id;
Or, if you want to pass the user parameter only once:
SELECT f.*, u.username
FROM Users u
INNER JOIN (
SELECT user_id, friend_id FROM Friends
UNION
SELECT friend_id, user_id FROM Friends
) f ON f.friend_id = u.user_id
WHERE f.user_id = 1
See the demo.
You need to join on Friend_id and select user_id from Friends table.
SELECT f.user_id,f.friend_id,u.username
FROM friends f JOIN users u
ON f.user_id=f.friend_id
This gives you output:
user_id | friend_id | username
1 | 3 | Wayne
2 | 1 | Elexis
You can union two qieroes which give you the result
CREATE TABLE friend
(`user_id` int, `friend_id` int)
;
INSERT INTO friend
(`user_id`, `friend_id`)
VALUES
(1, 3),
(2, 1),
(2, 4),
(1, 2)
;
CREATE TABLE users
(`user_id` int, `username` varchar(6), `password` varchar(7))
;
INSERT INTO users
(`user_id`, `username`, `password`)
VALUES
(1, 'elexis', '*******'),
(2, 'rooney', '*******'),
(3, 'wayne', '*******'),
(4, 'June', '*******')
;
SELECT f.*, u. username FROM friend f JOIN users u ON f.friend_id = u.user_id WHERE f.user_id = 1 AND f.`friend_id` NOT IN (SELECT user_id FROM friend WHERE friend_id = 1)
UNION
SELECT f.*, u.username FROM friend f JOIN users u ON f.user_id = u.user_id WHERE friend_id = 1
user_id | friend_id | username
------: | --------: | :-------
1 | 3 | wayne
2 | 1 | rooney
db<>fiddle here

Get user followers information along with count of user followers

I have a simple table below, User 2 & 3 are following user 1 , user 3 is following user 2
user_follower
user_id | follower_id
-----------------
1 | 2
1 | 3
2 | 3
User
id | name
---------------
1 | Kuldeep
2 | john
3 | Jacob
I need an sql query all the information of user 1 followers along with thier followers count so the expected result for user 1 would be
id name count
2 john 1
3 jacob 0
I am using PHP with mysql so whatever is the optmial way of doing it is welcome.
Thanks in advance
A self join of the user_follower table to construct the relationships, followed by a join to the User table to obtain the names will give you the result you want:
SELECT uf1.follower_id AS id, u.name, COUNT(uf2.follower_id) AS count
FROM user_follower uf1
LEFT JOIN user_follower uf2
ON uf1.follower_id = uf2.user_id
INNER JOIN User u
ON uf1.follower_id = u.id
WHERE uf1.user_id = 1
GROUP BY uf1.follower_id
Click the link below for a running demo:
SQLFiddle
Try as below :
select id,name,count(user_follower.user_id) as count
from user
left join user_follower
on user.id = user_follower.user_id
group by user.id
Check SqlFiddle

Check if row has specific childs on join

I want to make a SQL to get the user which name is Mark and are the author of the posts with ids 1 and 3.
NOTE: It is unknown how many posts I need to check for. So it might need to generate that part of the SQL query using PHP.
How can that be done?
Users Table:
+----+----------+
| id | name |
+----+----------+
| 1 | Mark |
| 2 | John Doe |
+----+----------+
Posts Table
+----+-------------+-------------+
| id | text | author_id |
+----+-------------+-------------+
| 1 | First Post | 1 |
| 2 | Second Post | 2 |
| 3 | Last Post | 1 |
+----+-------------+-------------+
This is just a sample case of use, not real data.
NOTE: I know how to check if user is author on one post, but not multiple in the same row. So basicly that is what I need help with, I guess it must be a left join.
For making the check for the user named Mark and check if he is author for post id 1 I do the following:
SELECT users.*
FROM users
INNER JOIN posts
ON users.id = posts.author_id
WHERE
users.name = 'Mark'
&&
posts.author_id` = 1
I just selected the id from users. If you need more columns then just add it to the select and the group by clause.
SELECT users.id
FROM users
INNER JOIN posts ON users.id = posts.author_id
WHERE users.name = 'Mark'
AND posts.author_id in (1,3)
GROUP BY users.id
HAVING count(distinct posts.author_id) = 2
Use a sub-query to find only users with both 1 and 3:
SELECT users.*
FROM users
WHERE users.name = 'Mark'
and 2 = (select count(distinct posts.id)
where users.id = posts.author_id
and posts.id IN (1,3))
SELECT users.name, posts.posts, posts.authorid
FROM users INNER JOIN posts ON users.id = posts.authorid where posts.authorid = 1
You need to use HAVING clause to achieve desired outcome:
SELECT users.name
FROM users
INNER JOIN posts
on users.id = posts.author_id
WHERE users.name = 'Mark'
GROUP BY users.name
HAVING COUNT(posts.author_id) > 1

Count occurrences of distinct values in 2 fields

I am trying to find a MySQL query that will find distinct values in a particular field, count the number of occurrences of that value in 2 fields (1_user, 2_user) and then order the results by the count.
example db
+------+-----------+-----------+
| id | 1_user | 2_user |
+------+-----------+-----------+
| 1 | 2 | 1 |
| 2 | 3 | 2 |
| 3 | 8 | 7 |
| 4 | 1 | 8 |
| 5 | 2 | 8 |
| 6 | 3 | 8 |
+------+-----------+-----------+
expected result
user count
----- -----
8 4
2 3
3 2
1 2
The Query
SELECT user, count(*) AS count
FROM
(
SELECT 1_user AS USER FROM test
UNION ALL
SELECT 2_user FROM test
) AS all_users
GROUP BY user
ORDER BY count DESC
Explanation
List all the users in the first column.
SELECT 1_user AS USER FROM test
Combine them with the users from the second column.
UNION ALL
SELECT 2_user FROM test
The trick here is the UNION ALL which preserves duplicate values.
The rest is easy -- select the results you want from the subquery:
SELECT user, count(*) AS count
aggregate by user:
GROUP BY user
and prescribe the order:
ORDER BY count DESC
SELECT u, count(u) AS cnt
FROM (
SELECT 1_user AS u FROM table
UNION ALL
SELECT 2_user AS u FROM table
) subquery
GROUP BY u
ORDER by cnt DESC
Take the 2 queries:
SELECT COUNT(*) FROM table GROUP BY 1_user
SELECT COUNT(*) FROM table GROUP BY 2_user
Now combine them:
SELECT user, SUM(count) FROM
((SELECT 1_user as user FROM table)
UNION ALL
(SELECT 2_user as user FROM table))
GROUP BY user, ORDER BY count DESC;
I think this what you are looking for since your expected result did not include 7
select usr, count(usr) cnt from
(
select user_1 usr from users
union all
select user_2 usr from users
) u
where u.usr in (select user_1 from users)
group by usr
order by count(u.usr) desc

MySQL count and join

I'm building a tasks system wich has 4 tables:
tasks
id | user_id | end_date
-------------------------
2 | 1 | 2011-02-10
users
id | username
--------------
1 | johndoe
--------------
2 | janedoe
roles
id | role_name
--------------
1 | coordinator
and tasks_roles_users
id | task_id | user_id | role_id
---------------------------------
1 | 2 | 2 | 1
Each task has a creator (ie: johndoe is the owner of task #2), and each task has several users with different roles on that task, in my example "janedoe" is the task #2 coordinator.
I'm stuck trying to show to "janedoe" and "johndoe" how many due tasks they have, and I'm having this problem since "johndoe" hasn't a role in the task, he's just the task owner.
So how can I tell to both they have 1 task due?
You can accomplish this by doing a LEFT JOIN
SELECT u.id, u.username,
IFNULL(t.Cnt,0) OwnCount,
IFNULL(tr.Cnt,0) RoleCount
IFNULL(t.Cnt,0) + IFNULL(tr.Cnt,0) TotalCount
FROM users u LEFT JOIN (
SELECT user_id, COUNT(*) cnt
FROM tasks
GROUP BY user_id
) t ON u.id = t.user_id
LEFT JOIN (
SELECT user_id, COUNT(*) cnt
FROM tasks_roles_users
GROUP BY user_id
) tr ON u.id = tr.user_id
WHERE t.user_id IS NOT NULL OR tr.user_id IS NOT NULL
A simple way to do this is to add an owner role and treat it like any other role. Another way would be to use a UNION.
SELECT COUNT(*) FROM tasks_roles_users WHERE user_id = "2"
That will get all tasks that "janedoe" has a roll in.
If there aren't very many rolls (say, less that 8), you might want to save the rolls as constants in your code, instead of making SQL queries for such a small thing.
define('ROLL_COORDINATOR', 1); // just an integer unique from other roll constants
SELECT COUNT(*) FROM tasks_roles_users WHERE user_id IN (SELECT id FROM users WHERE username = 'johndoe')
SELECT COUNT(*) FROM tasks_roles_users WHERE user_id IN (SELECT id FROM users WHERE username = 'janedoe')

Categories