mysql select statement with multiple where/conditions - mysql

I have the following two tables in mysql:
users:
+--------+-----------+
| userId | userName |
+--------+-----------+
| 1 | magnus |
| 2 | fabiano |
| 3 | alexander |
| 4 | veselin |
+--------+-----------+
games:
+--------+---------+---------+
| gameId | userId1 | userId2 |
+--------+---------+---------+
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 3 |
| 4 | 2 | 4 |
+--------+---------+---------+
How can I construct a single query such that I get this below output of say, fabiano's opponents:
output:
+--------+-----------+
| gameId | userName |
+--------+-----------+
| 1 | magnus |
| 3 | alexander |
| 4 | veselin |
+--------+-----------+
Edit1:
This was what I was trying and I wasn't able to get them into a single query:
select fabiano's opponents [select * from games where 2 in (userId1, userId2);]
read each of the rows, and check which of them is fabiano(2), and select the other userId
from the userIds of these opponents, get their name from users table
Edit2:
Inspired by the answers below, I wrote this (they work):
-- NO JOIN
select x.gameId, users.userName from
(
select gameId, userId2 as id from games where userId1=2
UNION
select gameId, userId1 as id from games where userId2=2
) as x, users
where users.userId = id;
-- NO JOIN, NO UNION
select x.gameId, users.userName from (
SELECT g.gameId,
CASE WHEN userId1 = 2
THEN userId2
WHEN userId2 =2
THEN userId1
END AS id
FROM games g) as x, users
where users.userId = id;

You can union the two sets of data together, viz all games where Fabiano is User 1, with all games that he is in the role of User 2:
SELECT x.Opponent
FROM
(
SELECT u.Name AS Opponent
FROM games g
INNER JOIN users u
ON g.userId2 = u.UserId
WHERE g.UserId1 = 2 -- Fabiano
UNION
SELECT u.Name
FROM games g
INNER JOIN users u
ON g.userId1 = u.UserId
WHERE g.UserId2 = 2 -- Fabiano
) AS x;
At this point as assume that Fabiano can't simultaneously both be User1 and User2, as we would need to consider UNION ALL vs UNION DISTINCT :)
This could also be tidied up a bit into:
SELECT x.Opponent
FROM
(
SELECT u.Name AS Opponent, g.UserId1 AS PlayerId
FROM games g
INNER JOIN users u
ON g.userId2 = u.UserId
UNION
SELECT u.Name, g.UserId2 AS PlayerId
FROM games g
INNER JOIN users u
ON g.userId1 = u.UserId
) AS x
WHERE x.PlayerId = 2; -- Fabiano

Try something like:
SELECT `gamess`.gameId, `users`.userName
FROM users INNER JOIN
(SELECT gameId, userId2 as userId
FROM games
WHERE userId1 = 2
UNION
SELECT gameId, userId1 as userId
FROM games
WHERE userId2 = 2) AS gamess
ON `gamess`.userId = `users`.userId

Doing this without a UNION clause will make it more performant
SELECT g.gameid,
CASE WHEN u1.userid = 2 -- fabino*
THEN u2.username
else u1.username END AS Opponent
FROM games g
LEFT JOIN users u1
ON g.userId1 = u1.UserId
LEFT JOIN users u2
on g.userid2 = u2.userid
WHERE (g.UserId1 = 2 OR g.userid2 = 2) -- fabino

SELECT us.*
FROM users us
INNER JOIN games gs ON us.userId = gs.userId1
GROUP BY us.userId ,us.userName

This query should be works all of common userid
SELECT x.Opponent
FROM
(
SELECT u.userName AS Opponent
FROM games g
INNER JOIN users u
ON g.userId2 = u.UserId
WHERE g.UserId1 in (select UserId from users where UserId in (select userid1 from games))
UNION
SELECT u.userName
FROM games g
INNER JOIN users u
ON g.userId1 = u.UserId
WHERE g.UserId2 in (select UserId from users where UserId in (select userid2 from games))
) AS x;

Related

Get list of groups user hasn't Joined, List of groups user didn't create

The user (Ben) has joined group 2 and group 3. How can I write this in a select query... I want to select from groups I haven't joined and groups I didn't create.
users_tbl table
user_id username
| 1 | ben
| 2 | betty
| 3 | tim
| 4 | jimmy
| 5 | sammy
user_groups table
user_id group_id
| 1 | 2
| 1 | 3
group_tbl table
group_id user_id
| 1 | 5
| 2 | 4
| 3 | 5
I am able to get the list of groups I didn't create using this query...
SELECT * FROM group_tbl LEFT JOIN users_tbl ON users_tbl.user_id = group_tbl.user_id WHERE group_tbl.user_id != ? ORDER BY RAND() LIMIT 10
How can I get the list of groups users hasn't joined?
You can do it if you do a LEFT join of group_tbl to users_tbl and return the unmatched rows of group_tbl:
SELECT g.*
FROM group_tbl g LEFT JOIN user_groups u
ON u.group_id = g.group_id AND u.user_id = 1
WHERE u.user_id IS NULL
Or with NOT EXISTS:
SELECT g.*
FROM group_tbl g
WHERE NOT EXISTS (
SELECT 1
FROM user_groups u
WHERE u.group_id = g.group_id AND u.user_id = 1
)
See the demo.
Results:
group_id
user_id
1
5

Many to Many relationships with an initial pivot condition

I have three tables groups, users and group_user.
While groups and users have an id and name column, the bellow is
the group_user table
+----+----------+---------+
| id | group_id | user_id |
+----+----------+---------+
| 12 | 5 | 1 |
| 13 | 5 | 8 |
| 14 | 5 | 7 |
+----+----------+---------+
The issue am facing is, I have a user with id 7, and am trying
to get the group of this user (which is 5 from above schema diagram), then retrieve every other user
in that group (user with id 1 and 8).
I tried doing something like this:
select `groups`.id, `groups`.name, users.id, users.name from `groups`
left join group_user on `groups`.id = group_user.group_id and group_user.user_id = 7
left join users on group_user.user_id = users.id
And expectedly the result is not accurate
Please try following query:
select g.name group_name, u.name user_name from group_user gu
left join users u on u.id = gu.user_id
left join groups g on g.id = gu.group_id
where gu.group_id in (select group_id from group_user where user_id = 7)
You must join users to 2 copies of group_user and finally groups with INNER joins:
select gu2.group_id, g.name group_name, u.id user_id, u.name user_name
from `users` u
inner join group_user gu on gu.user_id = u.id
inner join group_user gu2 on gu2.group_id = gu.group_id and gu2.user_id = 7
inner join `groups` g on g.id = gu2.group_id
See a simplified demo.

How can I get the name of each user by his id?

I have this query:
SELECT DISTINCT p1.rootid AS user_id, p1.rid AS friend_id
FROM relations p1
WHERE rootid = 1246
OR rootid IN (SELECT p2.rid
FROM relations p2
WHERE rootid = 1246);
The result of it is something like this:
Also I have a table which contains names. Something like this:
// users
+------+_--------+
| id | name |
+------+---------+
| 1246 | Jack |
| 1247 | Peter |
| 1246 | Ali |
| . | . |
| . | . |
| . | . |
+------+---------+
Now I want to get names instead of ids in the output. Noted that both user_id and friend_id refer to users table. How can I do that?
Try something like this,
SELECT u1.name user_name, u2.name friend_name from relations r
INNER JOIN users u1 ON u1.id = r.user_id
INNER JOIN users u2 ON u2.id = r.friend_id
where r.user_id = 1246
Hope this will solve your problem.
Try this :
SELECT DISTINCT u.name AS user_name, f.name AS friend_name
FROM relations p1
INNER JOIN user u ON u.id = p1.rootid
INNER JOIN user f ON f.id = p1.rid
WHERE rootid = 1246
OR rootid IN (SELECT p2.rid
FROM relations p2
WHERE rootid = 1246);

mysql select a value within a select

I have an implementation messages system.
My problem is, I would like to know whether a user already has a thread with another user and if so what is the mid
I have a messages_recips table which look like this
---------------------------
| mid | seq | uid | status|
|--------------------------
| 4 | 1 | 1 | A |
| 4 | 1 | 2 | A |
---------------------------
if user id 1 having a thread with user id 2 I hold 2 rows with same mid.
I know I can create 2 sqls to achieve what I'm asking for, but I'm trying to do it in 1 sql.
As noted by Waqar Janjua, the key to this is a self-join query:
SELECT m1.mid
FROM messages_recips AS m1
JOIN messages_recips AS m2 ON m1.mid = m2.mid
WHERE m1.uid = 1
AND m2.uid = 2
I think you have to write a self-join query:
Select u.uid, u1.uid from tablename u
INNER JOIN tablename u1 on u.mid = u1.mid
You will get all the users who have the same mid.
In order to get only user1 and user2 records you have to place a where clause at the end of the query lik this.
Select u.uid, u1.uid from tablename u
INNER JOIN tablename u1 on u.mid = u1.mid
Where ( u.uid In ( 1,2 ) OR u1.uid In ( 1,2 ) ) ;

LEFT JOIN 3 columns to get username

I have three columns I need to join which comes from 3 different tables,
Contributions table:
+-----------+---------------------+
| record_id | contributor_user_id |
+-----------+---------------------+
| 1 | 2 |
+-----------+---------------------+
| 1 | 5 |
+-----------+---------------------+
Members table:
+--------------+---------+
| username | user_id |
+--------------+---------+
| Test | 1 |
+--------------+---------+
| Test2 | 5 |
+--------------+---------+
| Test3 | 6 |
+--------------+---------+
Records table:
+---------+-----------+
| user_id | record_id |
+---------+-----------+
| 28 | 1 |
+---------+-----------+
For what I need to return is the username and user_id for displaying the record owner. Also, display the username and the user_id, but this can be multiple (more than 1+ user). I've tried this:
SELECT usr.username,
usr.user_id,
rec.record_id,
contrib.record_id,
contrib.contributor_user_id
FROM
(
records rec
INNER JOIN members usr ON rec.user_id = usr.user_id
# this returns records as NULL
LEFT OUTER JOIN contributions contrib ON rec.record_id = contrib.record_id AND contrib.contributor_user_id = usr.user_id
# this works, but I need the username to be displayed too
LEFT OUTER JOIN contributions contrib ON rec.record_id = contrib.record_id
)
WHERE rec.record_id = 1
Try nesting the join for contributing users inside of the left join to contributions.
SELECT u.username, u.user_id, r.record_id, u2.username as ContributorName, u2.user_id as ContributorId
FROM records r
INNER JOIN members u
ON r.user_id = u.user_id
LEFT JOIN contributions c
INNER JOIN members u2
ON c.contributor_user_id = u2.user_id
ON r.record_id = c.record_id
WHERE r.record_id = 1
SELECT
usr.username AS record_owner
, usr.user_id AS record_owner_id
, rec.record_id
, con.contributor_user_id AS contributor_id
, contributors.username AS contributor_name
FROM
records rec
INNER JOIN
members usr
ON rec.user_id = usr.user_id
LEFT OUTER JOIN
contributions con
ON rec.record_id = con.record_id
INNER JOIN
members contributors
ON con.contributor_user_id = contributors.user_id
WHERE
rec.record_id = 1