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

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);

Related

MySQL where in list but not in temp table

I am considering the following 2 tables
|------------| |-----------|
| user_roles | | roles |
|============| |===========|
| user_id | | role_id |
| role_id | | code_name |
|------------| |-----------|
I want to get all user_roles where user_id in a given list of user_ids. But I want to exclude all users who have a role with code_name = 'special_role'.
What would be the best way to do this?
For the purpose of an example, lets say I have the following:
user_roles: roles:
| user_id | role_id | | role_id | code_name |
|=========|=========| |=========|==============|
| 1 | 1 | | 1 | special_role |
| 1 | 2 | | 2 | another_role |
| 2 | 2 | |---------|--------------|
| 3 | 2 |
|---------|---------|
My thought was to use temp tables, like:
create temporary table if not exists all_user_ids as (
select ur.user_id as user_id, ur.role_id as role_id
from user_roles ur
where ur.user_id in (1,2,3)
);
create temporary table if not exists special_user_ids as (
select aui.user_id as user_id
from all_user_ids aui
join roles r on r.role_id = aui.role_id
where r.code_name = 'special_role'
);
create temporary table if not exists non_special_user_ids as (
select aui.user_id as user_id
from all_user_ids aui
where aui.user_id not in (special_user_ids.user_id)
);
Then for my final result, I could do:
select ur.user_id, ur.role_id
from user_roles ur
where ur.user_id in (non_special_user_ids.user_id)
But there's got to be a better way?!
You can use window functions - if you are running MySQL 8.0:
select *
from (
select ur.*, r.code_name, max(r.code_name = 'special_role') over(partition by user_id) has_special_role
from user_roles ur
inner join roles r on r.role_id = ur.role_id
) t
where has_special_role = 0
In earlier versions, one method is not exists:
select ur.*
from user_roles ur
where not exists (
select 1
from user_roles ur1
inner join roles r1 on r1.role_id = ur1.role_id
where ur1.user_id = ur.user_id and r1.code_name = 'special_role'
)
Just join. This should be pretty fast assuming you have keys set up.
SELECT * FROM user_roles JOIN role ON user_roles.role_id = role.role_id
WHERE user_roles.user_id IN(1,2,3 ...) AND role.code_name != "special_role"
Misunderstood the ask. If you want no users that have a special role at all:
SELECT * FROM user_roles WHERE user_id NOT IN(
SELECT user_id FROM user_roles JOIN role ON user_role.role_id = role.role_id
WHERE role.role_code = 'special_role')
AND user_id IN (1, 2, 3 ...)
Use IN and NOT IN for the 2 conditions:
select *
from user_roles
where user_id in (<list of usr_ids>)
and user_id not in (
select user_id from user_roles
where role_id = (select role_id from roles where code_name = 'special_role')
)
See the demo.

Select a specific row with additional column that its value is from another column in one table

Suppose I have a table named users consist of columns: user_id, user_name, user_created_by.
+------------------+----------------------+-------------------+
| user_id + user_name + user_created_by +
+------------------+----------------------+-------------------+
| 1 | John | 1 |
| 2 | Ann | 1 |
| 3 | Paul | 2 |
| 4 | King | 2 |
| 5 | Dirk | 3 |
+------------------+----------------------+-------------------+
The value of user_created_by is the user_id who created that record. Now, I want to make a query that results one specific row with added column let's say user_created_by_name which is the user_name of the user_id from the user_created_by. Suppose we want to get "Paul"'s record with who (the name) create it (temporary new column). For ease of understanding this is my expected result:
+----------+--------------+-------------------+------------------------+
| user_id | user_name | user_created_by | user_created_by_name |
+----------+--------------+-------------------+------------------------+
| 3 | Paul | 2 | Ann |
+----------+--------------+-------------------+------------------------+
this is my query using codeigniter:
$query=$this->db->query("SELECT *,
(SELECT user_name FROM users WHERE user_id = user_created_by)
AS "user_created_by_name" FROM users WHERE user_id=3);
But my result are:
+----------+--------------+-------------------+------------------------+
| user_id | user_name | user_created_by | user_created_by_name |
+----------+--------------+-------------------+------------------------+
| 3 | Paul | 2 | NULL |
+----------+--------------+-------------------+------------------------+
You culd use a self join (join the same table two time) using alias for fere to the tables as different sets of data
SELECT a.user_id, a.user_name, a.user_created_by, b.user_name as user_created_by_name
from users a
inner join user b on a.user_created_by = b.user_id
where a.user_id = 3
use self join
select u1.user_id, u1.name as user_name,
u2.user_created_by
,u2.user_name as createdby from users u1
join users u2 on u1.user_id=u2.user_created_by
where u1.user_id=3
You can solve this problem using a JOIN.
$sql = "SELECT users.user_id, users.user_name, user_created_by_name.user_name,
FROM users JOIN users AS user_created_by_name ON users.user_id = user_created_by_name.user_id WHERE users.user_id = 3";
$query=$this->db->query($sql);
If you you have users that were not created by another user use a LEFT JOIN instead:
$sql = "SELECT users.user_id, users.user_name, user_created_by_name.user_name,
FROM users LEFT JOIN users AS user_created_by_name ON users.user_id = users.user_id WHERE user_created_by_name.user_id = 3";
$query=$this->db->query($sql);
This will work:
SELECT a.user_id as User_id,
a.user_name as Name,
b.user_id as Created_by_user_id,
b.user_name as Created_by_name
FROM users AS a
INNER JOIN users AS b
ON a.user_id = b.user_created_by
WHERE a.user_id = 3
It is called a self-join, which is used when combining two records of the same table.

join pivot table in mysql

How to join different tables with pivote table
I have 4 tables like
users
id | name |
-------------
1 | abc |
2 | ccc |
user_profile
id | user_id | email |
-------------------------------
1 | 1 | abc#gmail.com
2 | 2 | ccc#gmail.com
skills
id | skill_name |
--------------------------
1 | java |
2 | php |
user_skills
user_id | skill_id |
---------------------------
1 | 1 |
1 | 2 |
2 | 1 |
The result should be
name | email | skills |
----------------------------------
abc |abc#gmail.com | java, php |
ccc |ccc#gmail.com | java |
I am able to join multiple tables but I have problem joining pivote
I have tried below with query
SELECT users.name,user_profiles.email, group_concat(programs.name)
from users
JOIN user_profiles on user_profiles.user_id = users.id
LEFT JOIN user_skills on user_skills.user_id = users.id
LEFT JOIN skills on user_skills.skill_id = skills.id
GROUP BY users.id
Can anyone help me on this please??Thanks
You need GROUP_CONCAT to generate the CSV list of skills:
SELECT
u.name,
up.email,
GROUP_CONCAT(s.skill_name) AS skills
FROM users u
INNER JOIN user_profile up
ON u.id = up.user_id
LEFT JOIN user_skills us
ON u.id = us.user_id
INNER JOIN skills s
ON us.skill_id = s.id
GROUP BY
u.id, u.name, up.email;
Demo
Note that I group by both the user's id and name, because perhaps two users happen to have the same name. Follow the link below for a running SQLFiddle.
Your query should work. Perhaps the problem is the reference to programs rather than skills:
select u.name, up.email, group_concat(s.name)
from users u join
user_profiles up
on up.user_id = u.id left join
user_skills us
on us.user_id = u.id left join
skills s
on us.skill_id = s.id
group by u.name, up.email;

mysql select statement with multiple where/conditions

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;

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