I want to make a selection that look up values of ID to Username from two columns in the same table:
Table: Gift
FromID ToID
1 2
2 6
3 2
5 3
TableL Users
UserID Username
1 A
2 B
3 C
4 D
5 E
6 F
Expected Output:
FromUser ToUser
A B
B F
C B
E C
Here is one trick using JOIN with IN condition
SELECT Max(CASE WHEN FromID = u.UserID THEN Username END),
Max(CASE WHEN ToID = u.UserID THEN Username END)
FROM users u
JOIN gift g
ON u.UserID IN ( g.FromID, g.ToID )
GROUP BY FromID,
ToID
Or you need to join the users table twice
SELECT f.Username,
t.Username
FROM gift g
LEFT JOIN users f
ON f.UserID = g.FromID
LEFT JOIN users t
ON t.UserID = g.ToID
Looks like you need a recap on how to work with several relationships between the same two tables.
Your gift table has a relationship that describes who gave the gift - I call it giver here; and a relationship that described who received the gift - I call it receiver here. Both relationships from gift are many-to-one towards the users table.
You simply join the same table twice and give that table a good correlation name - giver and receiver in my example - to show in the code what you're using them for.
Like so:
WITH
gift(fromid,toid) AS (
SELECT 1,2
UNION ALL SELECT 2,6
UNION ALL SELECT 3,2
UNION ALL SELECT 5,3
)
,
users(userid,username) AS (
SELECT 1,'A'
UNION ALL SELECT 2,'B'
UNION ALL SELECT 3,'C'
UNION ALL SELECT 4,'D'
UNION ALL SELECT 5,'E'
UNION ALL SELECT 6,'F'
)
SELECT
giver.username as fromUser
, receiver.username as toUser
FROM gift
JOIN users AS giver
ON gift.fromid=giver.userid
JOIN users AS receiver
ON gift.toid =receiver.userid
ORDER BY 1,2
;
fromUser|toUser
A |B
B |F
C |B
E |C
Related
I have a mySQL database in which I'm trying to output a list of users and their assigned, administrative roles. My tables look something like:
Users:
-------
- id
- fname
- lname
Role_Names
-----------
- rn_id
- role_name
Roles
---------
- role_id
- user_id
here's some data:
Users:
-------
1 'Chris' 'Christy'
2 'Brian' 'Bobson'
3 'Jen' 'Sanders'
Role_Names
--------------
1 'admin'
2 'exec'
3 'employee'
Roles
-----------
1 1
1 2
1 3
2 3
3 3
3 2
and for my query, I'm using:
SELECT Users.fname, Role_Names.role_name from Users INNER JOIN
Roles on Users.id = Roles.user_id
INNER JOIN Role_Names
ON Roles.rn_id = Roles.role_id;
It only seems to be outputting roles for the 1st user_id in the Roles table. And it's outputting more than 1 of the same record. For example, my output looks like:
first_name role_name
--------------------------------------
Chris exec
Chris exec
Chris exec
Chris employee
Chris employee
Chris employee
Chris admin
Chris admin
Chris admin
whereas I was hoping for something more like:
first_name role_name
--------------------------------------
Chris employee
Chris admin
Chris exec
Brian employee
Jen employee
Jen exec
...
At tis point I'm not sure if it's my table structure that is flawed or if I'm using joins incorrectly or if it's that plus a bunch of other stuff I don't even know about. Can someone help point me in the right direction?
Stare at this piece of your query: ON Roles.rn_id = Roles.role_id;
It is not what you meant!
Here is the fixed query (with clearer formatting):
SELECT Users.fname, Role_Names.role_name
FROM Users AS u
INNER JOIN Roles AS r ON u.id = r.user_id
INNER JOIN Role_Names AS rn ON rn.rn_id = r.role_id
Tip: Many:many mapping tables (your Roles) are typically named by the the two things it relates. So I suggest User_Roles. Then the 3rd table can be simply Roles. That leads to
SELECT Users.fname, Role_Names.role_name
FROM Users AS u
INNER JOIN User_Roles AS ur ON u.id = ur.user_id
INNER JOIN Roles AS r ON r.rn_id = ur.role_id
use distinct
with Users as
(
select 1 id, 'Chris' fname, 'Christy' lname
union all
select 2 , 'Brian', 'Bobson' union all
select 3 ,'Jen' , 'Sanders'
),Role_Names as
(
select 1 rn_id, 'admin' role_name
union all
select 2 , 'exec' union all
select 3 , 'employee'
) , Roles as
(
select 1 role_id,1 user_id
union all
select 1,2 union all
select 1,3 union all
select 2 , 3 union all
select 3 , 3 union all
select 3 , 2
) SELECT distinct Users.fname, Role_Names.role_name
from Users left JOIN
Roles on Users.id = Roles.user_id
left JOIN Role_Names
ON Role_Names.rn_id = Roles.role_id
you missed join in your query
JOIN Role_Names ON Roles.rn_id = Roles.role_id -- here both side you use Roles
You can use DISTINCT like following.
SELECT DISTINCT Users.fname, Role_Names.role_name from Users INNER JOIN
Roles on Users.id = Roles.user_id
INNER JOIN Role_Names
ON Roles.rn_id = Roles.role_id;
Try using below query.
SELECT Users.fname, Role_Names.role_name
from Roles RIGHT OUTER JOIN
Users on Users.id = Roles.user_id
INNER JOIN Role_Names
ON Roles_Names.rn_id = Roles.role_id;
I am looking to show a mutual friends function but my user friends list is stored on another table.
I want to know if it's possible to use the data of each row as a clause for join B
SELECT * FROM ( SELECT * FROM `users`) a
CROSS JOIN (SELECT COUNT(*) AS MUTUAL_FRIENDS
FROM `user_friends` WHERE `friend_to` = `a`.`userid`) b
ORDER BY `b`.`MUTUAL_FRIENDS` ASC
What I am looking to do is use the userid from users table as a clause for the join with:
`friend_to` = `a`.`userid`
Expected results:
+--------=+---------+-----------+--------------+
| userid | Username |Photo_URL |MUTUAL_FRIENDS|
+---------+---------+-----------+--------------+
1 Somename1 /image1.png 3
4 Somename4 /image4.png 2
2 Somename2 /image2.png 1
3 Somename3 /image3.png 0
5 Somename5 /image5.png 0
Friends table:
+--------=+---------+-----------+
| friend_id | userid |friend_to |
+---------+---------+-----------+
1 1 2
2 2 1
3 1 3
4 3 1
5 1 4
6 4 1
Users Table
+--------=+---------+-----------+
| userid | Username |Photo_URL |
+---------+---------+-----------+
1 Somename1 /image1.png
2 Somename2 /image2.png
3 Somename3 /image3.png
4 Somename4 /image4.png
5 Somename5 /image5.png
Or am I doing this totaly wrong?
Here is one approach.
With CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a
CROSS JOIN Friends b
WHERE a.userid = b.friend_to and a.friend_to = b.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
Without CROSS JOIN
SELECT u.userid,u.Username,u.Photo_URL,IFNULL(Num,0) MUTUAL_FRIENDS
FROM Users u
LEFT JOIN (SELECT userid, COUNT(*) Num
FROM (SELECT a.userid
FROM Friends a, Friends b
WHERE a.friend_to = b.userid and b.friend_to = a.userid) r
GROUP BY userid) k ON u.userid = k.userid
ORDER BY MUTUAL_FRIENDS DESC, u.userid
I will try to explain little by little and please correct me if there is error.
The condition a.friend_to = b.userid and b.friend_to = a.userid is
used to select only mutual friend. Then if a user has this kind of
"mutual connection," the corresponding userid will appear once.
Get the count along with the userid.
Left join the userid and count table.
Result
userid Username Photo_URL MUTUAL_FRIENDS
1 Somename1 /image1.png 3
2 Somename2 /image2.png 1
3 Somename3 /image3.png 1
4 Somename4 /image4.png 1
5 Somename5 /image5.png 0
Given the data, user1 is mutual friend of user2, user3 and user4. User2 is only mutual friend of user 1 and so as user 3 and user4.
With CROSS JOIN SQL Fiddle
Without CROSS JOIN SQL Fiddle
I have 3 tables:
tbl_user stores all user details (user_id,name,address)
user_id name address
1 a (shop) home
2 b (shop) bakerstreet
3 c (staff) wallstreet
4 d (staff) georgia
5 e (staff) sydney
tbl_user_group stores user type (user_id,user_type : 1=shop_owner,2=staff)
user_id user_type
1 1
2 1
3 2
4 2
5 2
tbl_user_association holds the shop_owner and staff relation (shop_owner_id, staff_id)
shop_owner_id staff_id
1 3
1 4
1 5
2 3
2 4
desired result
i want to display the list of staffs and the respective shops that they are associated with as follows:
user_id staff_name shop_owner
3 c a,b
4 d a,b
5 e a
I tried using the group_concat as mentioned here. The query is as follows:
SELECT
u.id AS user_id,
u.name AS staff_name,
(SELECT GROUP_CONCAT(u.name separator ',') FROM tbl_user u WHERE u.id = ua.shop_owner_id) AS
shop_owner
FROM tbl_user u
JOIN tbl_user_group ug ON u.id = ug.user_id
LEFT JOIN tbl_user_association ua ON u.id = ua.staff_id
WHERE ug.user_type = 2
GROUP BY u.id
But it returns single row of staffs as below. where have i gone wrong?
user_id staff_name shop_owner
3 c a
4 d a
5 e a
This is how I'd do it:
SELECT
u.user_id,
u.name,
GROUP_CONCAT( so.name )
FROM
tbl_user_group ug
INNER JOIN tbl_user u
ON ( ug.user_id = u.user_id )
INNER JOIN tbl_user_association ua
ON ( ua.staff_id = u.user_id )
INNER JOIN tbl_user so -- here join again the user table to get shop owners names
ON ( ua.shop_owner_id = so.user_id )
WHERE
ug.user_type = 2
GROUP BY
u.user_id;
I have database with following data structure with sample data. Each company have multiple members. The relationship is in the company_member table. Please note only required fields I have given below.
company
id title
1 company-1
2 company-2
company_member
companyid memberid
1 1
1 2
1 3
2 4
2 5
2 6
member
id firstname member_type_id
1 Name-1 2
2 Name-2 3
3 Name-3 3
4 Name-4 3
5 Name-5 2
6 Name-6 1
member_type
id user_level
1 0
2 1
3 2
I want list of unique companies with one member from each. But the member should be the lowest user_level within the company. i.e, following result should come;
result
companyid company_title memberid member_name user_level
1 company-1 1 Name-1 1
2 company-2 6 Name-6 0
I want to know how to get one member with lowest user level among the same company.
This is a bit complicated one, however this is one way of doing it using not exists, for bigger tables its wise to use not exits since using pivot tables it will not use index.
select
c.id,
c.title,
m.id as member_id,
m.firstname,
mt.user_level
from company_member_map cmp
join company c on c.id = cmp.companyid
join member m on m.id = cmp.memberid
join member_type mt on mt.id = m.member_type_id
where not exists
(
select 1 from company_member_map t1
join member t2 on t2.id = t1.memberid
join member_type t3 on t3.id = t2.member_type_id
where
t1.companyid = cmp.companyid
and t3.user_level < mt.user_level
)
DEMO
Finally I found solution:
select c.id companyid, c.title company_title, m.firstname member_name, mt.user_level
from company c
inner join company_member cm on cm.companyid = c.id
inner join member m on m.id = cm.memberid
inner join member_type mt on mt.id = m.member_type_id
inner join
(select c1.id companyid, mt1.user_level
from company c1
join company_member cm1 on cm1.companyid = c1.id
join member m1 on m1.id = cm1.memberid
join member_type mt1 on mt1.id = m1.member_type_id
group by c1.id,m1.id
order by user_level asc
) sq on c.id = sq.companyid and sq.user_level = mt.user_level
group by c.id;
Correct this, if anyone have better solution or simplified solution.
Check this SQL Fiddle
I have a database with two tables users and orders
users: user_id(primary), fname, lname, email, password, gender
orders: order_no(primary), user_id(foriegn), beans, type, extras, city
The orders table have only users who submitted orders.
I need to know how to select all users with the count of their orders if they have orders or don't.
Additional Info posted as an answer....
users table:
user_id fname lname email password gender
1 a aa aaa 123 m
2 b bb bbb 34 f
orders table:
order_no user_id bean type extras city
1 2 s d rr ggg
2 2 s d rr ggg
how to select all users table columns plus orders count for a and b so the new table will be:
user_id fname lname email password gender orders_count
1 a aa aaa 123 m 0
2 b bb bbb 34 f 2
select U.user_id,
COUNT(O.user_id)
from users U
left join orders O on U.user_id=O.user_id
group by U.user_id
Based on the updated information, use:
SELECT u.*,
COALESCE(x.orders_count, 0) AS orders_count
FROM USERS u
LEFT JOIN (SELECT o.user_id,
COUNT(*) AS orders_count
FROM ORDERS o
GROUP BY o.user_id) x ON x.user_id = u.user_id
ORDER BY u.user_id
Your update is basically requesting what pcofre's answer already gives you. You just need to add the additional required columns to your select list and provide a column alias for the aggregate.
SELECT U.user_id,
U.fname,
U.lname,
U.email,
U.password,
U.gender,
COUNT(O.user_id) AS orders_count
FROM users U
LEFT JOIN orders O
ON U.user_id = O.user_id
GROUP BY U.user_id /*<-- Don't need to add other users
columns to GROUP BY in MySQL*/