friend in common query mysql - mysql

I have these 2 tables: users and friendship. i would like find the friends in common between two user, i tried to do some query with alias but doesn't show my results.
Table users
user_id | name | surname
1 Luca Jhon
2 Paul Red
3 Jin Blue
4 Diana Lars
Table friendship
id_friendship | id_user_sender | id_user_receive | confirm
1 1 2 2
2 2 3 2
3 1 3 2
4 1 5 2
Should be show this one if i am the user called Luca (id 1 ) and search the realtion with Paul (id 2)
name | surname | id_user |
Jin Blue 3
Any idea? Thank you

Friendship is, presumably, reciprocal. Your friendship table only has one-way relationships.
So, the idea is to create all possible friendships in both directions. Then to aggregate by the first and test the second for each of the users you are interested in:
select u.*
from (select id_user_sender as id1, id_user_receive as id2
from frienship f
union all
select id_user_receive as id1, id_user_send as id2
from frienship f
) f join
users u
on f.id1 = u.user_id
group by id1
having max(id2 = 1) > 0 and
max(id2 = 2) > 0;

Related

Sql query with 2 join and count numbers and group by

I want to use an join to list the car colors count, car type, and users name.
I have 3 table
Table 1 Useres
id|username|fullname
1 | test0 | xy xy
2 | test1 | yx yx
Table 2 Car Type
id|car_type|user_id
1 | Ford | 1
2 | BMW | 2
3 | Ford | 1
4 | Skoda | 1
5 | BMW | 2
Table 3 Car Color
id| Color |user_id|car_id
1 | Red | 1 |1
2 | Blue | 2 |2
3 | Red | 2 |5
4 | Red | 1 |3
5 | Red | 1 |4
6 | Green | 1 |4
One car has 2 color
The result should be:
countType | CountColor | UserName
3 | 4 | test0
2 | 2 | test1
I tryed this:
SELECT
test as BlogsPost,
test2 as CommenstPost,
u.name
FROM users u
LEFT JOIN (
select COUNT(blogs.user_id) as test FROM blogs GROUP by blogs.user_id) blogs
on blogs.user_id=u.id
LEFT JOIN (
select COUNT(comments.user_id) as test2 FROM comments GROUP by comments.user_id) comments
on comments.user_id=u.id
GROUP by users.id
If I understand your question correctly with reference to your actual code section what you want is a list of users with how many blogs they have and how many comments they have. Now if you were wanting to count one matching table you could just do this:
SELECT
U.NAME
,COUNT(1) AS BLOG_COUNT
FROM USERS U
LEFT JOIN BLOGS B
ON B.USER_ID = U.ID
GROUP BY U.NAME
But since you are wanting to count two tables you have to do it slightly differently. There's a few ways of doing it but the way I like is like this:
SELECT
U.NAME
,B.BB_COUNT AS BLOG_COUNT
,C.CC_COUNT AS COMMENT_COUNT
FROM USERS U
LEFT JOIN
(
SELECT
BB.USER_ID
,COUNT(1) AS BB_COUNT
FROM BLOGS BB
GROUP BY BB.USER_ID
) B
ON B.USER_ID = U.ID
LEFT JOIN
(
SELECT
CC.USER_ID
,COUNT(1) AS CC_COUNT
FROM COMMENTS CC
GROUP BY CC.USER_ID
) C
ON C.USER_ID = U.ID
That may or may not be the most efficient way but in my experience it works pretty well and it's simple to understand. It all depends a lot on the number of rows in the tables and indexes etc. Usually the idea is to narrow down rows returned as fast as possible. In this case you'll have two sub queries but they'll end up with only as many rows as you have users basically.
Another thing to note, this will return all users, period. That may not be what you want. You might want only a subset of users. If so this inner select may not be the most efficient because you're doing calculations on users that may not be in the final result, wasting time. However I may be getting off topic.
I agree with the comment that states the table design is not really well constructed yet for you to achieve the counts you want you will need to do subqueries like this:
SELECT
(SELECT count(1) from CarType where user_id=username) as countType,
(SELECT count(1) from CarColor where user_id=username) as countColor,
username from (
SELECT username from Users
) a
As a suggestion for design:
Table Users
Table Cars
Table Colors
Then you have a Relationship table where you have user_id, car_id, color_id
This would be the proper table design for this structure

How to add temporary column with data with MYSQL?

I have 2 tables : Users & User_friends, the users table holds data of the user like name, password, id, etc. the user_friends table holds both of the id's of user and another user from the same users table:
id | user_id | friend_id
1 | 1 /Ben | 2 / Dave
2 | 1 /Ben | 3 / Rob
So as you can see - Ben is friend with both Dave and Rob ( the names are just for visual representation).
I want to create a query that get all the users - but adds an indicator for
who is friend with the logged user - which be passed as a paramater from PHP later on (bear with me here please).
The result i'm looking for is something like this:
id | user | isFriend
2 | john | true
3 | bob | false
4 | sam | false
Is it possiable with MYSQL or should i do it on the client side, with JavaScript?
Here are the tables.
Thanks
This query should give you the results you want. For each user in the users table, it gives you id, name and whether they are friends with (in this example) user 4 (this being the value you would pass as a parameter to the query):
SELECT u.id, u.name,
EXISTS(SELECT *
FROM user_friends
WHERE user_id = u.id AND friend_id = 4) AS isFriend
FROM users u
Results (for your sample data)
id name isFriend
1 roy 0
2 amit 1
3 oren 1
4 yaniv 0
5 shai 0
11 adi 0
12 eran 1
13 Nir 0
14 Ron 0
Updated SQLFiddle

Mysql finding results not present in jointable

I've got a mysql question that I haven't been able to figure out. Its a little bit different than the other questions I've found here on SO.
I've got three tables
users
____________
ID name
1 John
2 Mike
3 Susie
tasks
___________
ID Name
1 Brush Teeth
2 Shower
3 Check Email
users_tasks
_____________________
ID user_id task_id
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 1
Im trying to find out what users haven't completed what tasks yet. I would like the result set to look like this:
user_id task_id
__________________
2 3
3 2
3 3
The closest I have come is this query, which only gives me users that haven't completed at least one of the tasks, but doesn't give me the task.
select * FROM users
right JOIN users_tasks on users.id = users_tasks.user_id
right JOIN tasks on users_tasks.task_id = tasks.id
where tasks.id is null
I cant figure out how to return duplicate users and tasks based on what is missing form the join table.
Thanks in advance
An easy solution is just to require that the entry is not in your completed tasks table:
select * from users, tasks
where not exists (
select * from users_tasks
where users.id = users_tasks.user_id and tasks.id = users_tasks.task_id
);
Result:
+------+-------+------+-------------+
| id | name | id | name |
+------+-------+------+-------------+
| 3 | susie | 2 | Shower |
| 2 | mike | 3 | Check Email |
| 3 | susie | 3 | Check Email |
+------+-------+------+-------------+
One way to do this is to create a set representing the cartesian product of the users and tasks tables. This is what would be the result if every user had done every task. Then do a left join with the actual users_tasks table and filter for null to get the missing items:
select sub.*
from (
select u.id user_id, t.id task_id
from users u, tasks t
) sub
left join users_tasks ut on sub.user_id = ut.user_id and sub.task_id = ut.task_id
where ut.ID is null;

Group by either column

Sample Table:
User1 | User2
------+------
123 | 555
123 | 1
123 | 2
456 | 2
555 | 456
12 | 123
12 | 456
Input: I enter the list (123,456) to look at rows containing either of those values. Then I want MySQL to check the opposite/other column in that row, and group the output by that value.
Output:
User | Count(*)
-----+---------
555 | 2
2 | 2
1 | 1
555 count is 2 because row 123, 555 and row 555, 456 both contain one of the inputs: 123 and 456.
I've tried looking at the CASE keyword, because the obvious obstacle here is grabbing the opposite/remaining column and using that as one of the returned values.
Completely wrong, but one of my half-finished approaches.
SELECT user, count(*)
FROM friendships
WHERE User1 IN (123,456) AS user
OR User2 IN (123,456) AS user
the tricky part with this is your criteria is the IN() is looking in the users1 column and then tries to find duplicates in the user2 column... so you need a join with a UNION
SELECT user2, COUNT(*)
FROM
( SELECT user1, user2
FROM friends f
WHERE f.user1 IN(123, 456)
UNION ALL
SELECT f.user1, f.user2
FROM friends f
JOIN friends f1 ON f1.user1 = f.user2
WHERE f.user1 IN(123, 456)
)t
GROUP BY user2;
WORKING FIDDLE

UNION SELECT with dummy data

I want to create a limit of 6 rows with this logic:
Select user_id's that are in the friends list (and also in the same table)
if there are less that 6, select then another RANDOM users,but not in friends list (until limit of 6)
if there are not 6 user_id's, add some "dummy" users id (with id 0)
all "real" users must be distinct (with id > 0)
id | friends_list | name
1 2,3,5 John
2 1,7,9 Michael
3 1,2,5 Tom
4 3,2,6 Larry
The expected result must be something like this (for a given user e.g. id=1):
2, 3, 4, 0, 0, 0
You should probably store your data differently and use joins to select the data out of multiple tables. There are also other ways you might think about storing data also depending on your use cases.
PEOPLE TABLE
id | name
1 | John
2 | Michael
3 | Tom
4 | Larry
PEOPLE_FRIENDS TABLE
id | person_id | friend_id
1 | 1 | 2 //In this case John is friends with Michael
2 | 3 | 1 //In this case Tom is friends with John.
The following select would pull id's for John's friends.
SELECT * FROM PEOPLE `P` INNER JOIN PEOPLE_FRIENDS `PF` ON P.id = P.person_id WHERE P.id = 1
Again a million different ways to go about writing that query as well, but this will get you pointed in the right direction I think.