Mysql, double join that use the same table twice, but indirectly - mysql

There are plenty of question about join on the same table, but I can't find something related to my problem
I have two tables:
user (id, name)
friends (from, to)
And I have the following query. It is supposed to retrieve all users with their friends :
SELECT user.id, user.name, f.to, friend.id, friend.name
FROM user
LEFT JOIN friends f ON user.id = f.from
LEFT JOIN user friend ON user.id = f.to
LIMIT 0, 200
It returns something like this:
id name from to id name
1 bob 1 3 NULL NULL
1 bob 1 4 NULL NULL
2 toto 2 7 NULL NULL
The from and two are correct, but the second join doesn't seem to work. Do you have any ideas what is wrong with the second join ?

Try this:
SELECT user.id, user.name, f.to, friend.id, friend.name
FROM user
LEFT JOIN friends f ON user.id = f.from
LEFT JOIN user friend ON friend.id = f.to
LIMIT 0, 200
Note that I replaced user with friend in the join condition.

Related

Three way join with linking table

This is what I'd think is a fairly common pattern, but I'm just struggling with the appropiate query for it.
User Table
id
Member table
id
name
User Member link table
user_id
member_id
A user may exist in the user's table, but not have a row in the User Member link table.
I want to select all rows of the User table, and where a user has a link to a member in the user member link table to show the columns linked to them from the member table.
Here's what I've got, but it only gets the rows from the User table that are linked:
SELECT user.id, user.username, member.id, member.name
FROM users
LEFT JOIN user_member ON user.id = user_member.user_id
JOIN member ON user_member.member_id = member.id;
I should get something like this:
user.id user.username member.id member.name
1 bob null null
2 alice 10 Alice
3 jane 11 Jane
4 joe null null
Any suggestions?
I assume a member_id in the user_member table always has a corresponding row in the member table. First, join member and user_member. Second, join user.
SELECT user.id, user.username, member.id, member.name
FROM users
LEFT JOIN
(user_member INNER JOIN member ON user_member.member_id = member.id)
ON user.id = user_member.user_id;
Try using a CROSS JOIN
SELECT user.id, user.username, member.id, member.name
FROM users u
CROSS JOIN member m
LEFT JOIN user_member um
ON u.id= um.user_id
AND m.id= um.member_id

Using multiple columns in a join on same field in second table

Consider the following :
**Table 1 - record**
id (int primary key),
addedby (int),
editedby (int)
**Table 2 - users**
id (int primary),
name (shorttext)
**Sample Records**
record
0 1 1
1 1 2
users
1 user1
2 user2
What I need is so do a join to to be able to show the following :
record.id, users.addedby, users.editedby
I tried, amongst others, the following :
select record.id, users.name, users.name from record left join users on record.addedby=users.id left join users on record.editedby=users.id
However, it's not even logical that that will work, so I am a bit stuck.
Any help would be much appreciated. Thank you.
Just join the same table twice. Nothing unusual. You just have to alias the tables to be able to refer to them independently.
select r.id, u1.name added, u2.name editor
from record r
inner join user u1
on r.addedby = u1.id
inner join user u2
on r.editedby = u2.id
heres a demo
Use aliasses:
select record.id, users1.name, users2.name
from record
left join users users1 on record.addedby=users1.id
left join users users2 on record.editedby=users2.id

Get real friends from friendlist

I know there are plenty of results on this topic, but they didn't help me.
I have a friends table with user1 and user2.
A real friend is when user1 is friend with user2 and user2 is friends with user1.
A friend request is when user1 is friends with user2. It looks something like this:
user1 | user2
-------------
1 | 2
2 | 1
1 | 3
3 | 1
1 | 5
How could the query look to get the real friends of #1?
I tried this but it returned null:
SELECT user2 FROM friends WHERE user1 = 1 AND user2 = 1
Also how would the query look for the friend request?
SELECT a.user1 FROM friends AS a JOIN friends AS b
ON a.user2 = b.user1 AND a.user1 = b.user2
WHERE a.user2 = ?
Where ? denote the ID the the "original" user.
One way to get this is with a JOIN operation:
SELECT f.user2
FROM friends f
JOIN friends r
ON r.user1 = f.user2
AND r.user2 = f.user1
WHERE f.user1 = 1
Given that a "real friend" relationship is identified by the existence of two tuples, that is, a real friend relationship between 1 and n would be represented by two rows in the table: (1,n) and (n,1).
The predicates in the join condition limit the rows returned to those rows that have a matching "inverse" tuple.
NOTE: a JOIN operation usually performs better than an equivalent IN (subquery) or EXISTS (subquery) patterns, but that performance difference is negligible with small sets. It's with larger sets that the performance difference becomes noticeable.
An equivalent result can be returned (usually less efficiently) using an EXISTS predicate:
SELECT f.user2
FROM friends f
WHERE f.user1 = 1
AND EXISTS ( SELECT 1
FROM friends r
WHERE r.user1 = f.user2
AND r.user2 = f.user1
)
or an IN predicate:
SELECT f.user2
FROM friends f
WHERE f.user1 = 1
AND f.user2 IN ( SELECT r.user1
FROM friends r
WHERE r.user2 = f.user1
)
(If there's not a unique constraint on friends(user1,user2), then JOIN may return some duplicate rows which may not be returned by the other queries, but none of the queries guarantee that no duplicates are returned. If there's no unique constraint, and you don't want any duplicates returned, then you can either add a DISTINCT keyword after the SELECT at the beginning of any of those statements, -or- add a GROUP BY f.user2 at the end of any of those statements.
To make the result set more deterministic (i.e. return the same result each time the query is run), you could add an ORDER BY clause. (But it's not needed with the GROUP BY since MySQL implicitly does an ORDER BY on the GROUP BY expressions.)
FOLLOWUP
explain how I could bind this results with the name in the user table? thank you. And how do I get the "not real" friends?
To get the name from the user table, we just add a JOIN to the user table, assuming id is the primary key column, and the user1 and user2 columns are foreign keys to the user table...
SELECT f.user2
, u.name
FROM friends f
JOIN user u
ON u.id = f.user2
JOIN friends r
ON r.user1 = f.user2
AND r.user2 = f.user1
WHERE f.user1 = 1
A "not real" friends would be represented as a tuple (row in the table) (1,n) which does not have a corresponding inverse tuple (n,1). To find those rows we use an anti-join pattern, which is an OUTER join (return all rows from one side plus any matching rows), and then a predicate that excludes the rows where a match was found (checking for a NULL in a column that is guaranteed not to be null if there is a match is how we do that):
This will find all the (1,n) tuples where there isn't a matching (n,1):
SELECT f.user2
, u.name
FROM friends f
JOIN user u
ON u.id = f.user2
LEFT
JOIN friends r
ON r.user1 = f.user2
AND r.user2 = f.user1
WHERE r.user1 IS NULL
AND f.user1 = 1
We'd have to flip that around to get the other side, (n,1) rows which don't have a matching (1,n) row:
SELECT f.user1
FROM friends f
JOIN user u
ON u.id = f.user1
LEFT
JOIN friends r
ON r.user2 = f.user1
AND r.user1 = f.user2
WHERE r.user2 IS NULL
AND f.user2 = 1
SELECT user2 FROM friends
WHERE user1 = 1
AND user2 IN (SELECT user1 from friends where user2 = 1);

Single Row Friendship Database Schema with getting userid from one column or the other

I need help querying the friendID from a table.
My table stores the user id of two members who are friends together.
But in order to store a "friendhship" b/w two members I would have to store two records like this:
friendshipID | userID | friendID
1 | 5 | 10
2 | 10 | 5
Yet, that seems heavy for the DB when we really only need to store the first record as that is sufficient as it contains both ids of both members.
However, the trouble comes when I want to query the records of the friends of ID=5. Sometimes the ID is in the userID column and other times it is in the friendID column.
This is the query I am using:
SELECT *
FROM friends
WHERE userID = '5'
OR friendID = '5'
But what I want to do is something like this
SELECT
if $userID=5 then userID as myfriend
else friendID=5 then friendID as myfriend
FROM friends WHERE userID='5' OR myfriendID='5'
Hope that makes sense. In the end I would like to have all the friends ID's of member #5 and not bring up results with #5 as the friend or user....but just his friends.
This query would return the Id value, and name, of the friends of #5 as shown in this SQL Fiddle Example
SELECT f.FriendId AS FriendId
, u.Name AS FriendName
FROM FriendTable AS f
INNER JOIN UserAccount AS u ON f.FriendId = u.UserId
WHERE f.UserId = 5
UNION
SELECT f.UserId AS FriendId
, u.Name AS FriendName
FROM FriendTable AS f
INNER JOIN UserAccount AS u ON f.UserId = u.UserId
WHERE f.FriendId = 5
The UNION will remove duplicates, making this query work for both a single record of friends, or the 2 record friendship you mention in the comment. You shouldn't need the 2 record friendship though, because there is no new information being stored in the second record that you cannot get from only having one record.

MySQL left join to get last messages and usernames

I want to get all user names and last_messages with who the current user had conversation.
I have two tables:
Thread
User
So, if current user's id is 1, I should get rows for bob and mike, but I get empty result. Could you please help me to find the mistake.
SELECT * FROM thread
LEFT JOIN user
ON ((thread.user1_id!=current_user AND thread.user1_id=user.id)
OR (thread.user2_id!=current_user AND thread.user2_id=user.id))
WHERE current_user = 1;
Try this:
select
calls.*
from User
left join (
select
User.Name, thread.user2_id as Partner_id
from User join thread on thread.user1_id = user.id
union all
select
User.Name, thread.user1_id as Partner_id
from User join thread on thread.user2_id = user.id
) calls
on calls.partner_id = User.id
where User.id = 1
Note how the double join from thread to User is done - once against both sides of the call in the subquery as an inner join, then a second time as outer table of an outer join.
Please try in this way
SELECT * FROM thread t
LEFT JOIN user u1
ON t.user1_id = u1.id
LEFT JOIN user u2
ON t.user2_id = u2.id
where t.user1_id = '1' or t.user2_id = '1'
should get rows for bob and mike (Thread row 1 & 2 )