Joining 3 Tables With Multiple Column Connections - mysql

I am struggling to get the correct syntax for what I need and wondered if anyone could help?
I have 3 tables: users, owneditems and shopitems
From users I need to get userid and city
From owneditems I need to get userid and itemid
From shopitems I need to get id and city
userid on owneditems and users will be the same
itemid on owneditems will be the same as id on shopitems
city on shopitems and users will be the same
What I'm after is to find out which city the users are in and tie up which items they own in that city.
The syntax I tried using was
SELECT users.city, users.id, shopitems.city, shopitems.id, owneditems.itemid, owneditems.userid
FROM users, shopitems, owneditems
WHERE users.city = shopitems.city
AND owneditems.itemid = shopitems.it
AND users.id = owneditems.userid

It is not exactly clear what you are trying to do, but have you tried using a LEFT JOIN instead of the INNER JOIN:
select u.city,
u.id,
s.city,
s.id,
o.itemid,
o.userid
from users u
left join owneditems o
on u.id = o.userid
left join shopitems s
on u.city = s.sity
and o.itemid = s.itemid

Related

Mysql simulating FULL OUTER JOIN

I have 2 tables users and orders, I want get users and his orders count
SELECT `users`.*, `orders`.*,count(*) FROM `users` LEFT JOIN orders ON
`users`.`id` = `orders`.`user_id`
UNION SELECT `users`.*, `orders`.*,count(*) FROM users
RIGHT JOIN orders ON `users`.`id` = `orders`.`user_id`
This query select users and order count of users which have order, but not select users who not have orders .
What I want get
user orders
John 5
Thomas 0
Mike 8
What I get
user orders
John 5
Mike 8
How to get also users who not have orders ?
You don't need a full outer join for this. A left outer join should be fine, assuming that all the users in the orders table have a valid reference to the users table:
SELECT u.*, count(o.user_id)
FROM `users` u LEFT JOIN
orders o
ON u.`id` = o.`user_id`
group by u.id
The following query will give you a list of all users and the count of their orders, including 0 if that user has no orders.
Also, are you sure that ORDER_ID is the FK to the user table? That seems counter-intuative to me...
SELECT U.NAME
,COUNT(O.ORDER_ID)
FROM USERS U
LEFT OUTER JOIN
ORDERS O
ON U.ID = O.ORDER_ID
GROUP BY
U.NAME

MYSQL compare values from same columns

Okay I tried to look all over stackoverflow, and the closest solution I found is this:
mysql AND clause on same column multiple times
But I can't use statements and "having" syntax won't work because of group by. There MUST be a simple solution to this.
The 2 tables looks like this (simplified):
users:
uid name
1 person 1
2 person 2
3 person 3
categories:
uid value
1 actor
1 musician
2 actor
3 dancer
4 musician
4 dancer
I want to get the uid of those that are 2 values at the same time. For example, I want to get the UID that is an actor AND a musician. Not just one value, but both of them must be required!
First I tried this:
SELECT users.uid, users.name
FROM
users
LEFT OUTER JOIN categories ON users.uid = categories.uid
WHERE (categories.value = 'actor' AND categories.value = 'musician')
GROUP BY u.uid;
This of course does not work since one row can't have 2 values.
Does anyone know a solution?
You can JOIN to the categories table multiple times to get the result:
SELECT users.uid, users.name
FROM users
INNER JOIN categories c1
ON users.uid = c1.uid
INNER JOIN categories c2
ON users.uid = c2.uid
WHERE c1.value = 'actor'
AND c2.value = 'musician';
See SQL Fiddle with Demo
SELECT users.uid, users.name
FROM users
LEFT JOIN categories ON users.uid = categories.uid
WHERE categories.value in ('actor', 'musician')
GROUP BY u.uid, users.name
having count(distinct categories.value) = 2;
Use a having clause
SELECT u.uid, u.name
FROM users u
LEFT OUTER JOIN categories c ON u.uid = c.uid
WHERE c.value = 'actor' OR c.value = 'musician'
GROUP BY u.uid
having count(distinct c.value) > 1
If you really do not want to use having you could try this:
SELECT uid, name
FROM users
WHERE
uid IN (SELECT uid FROM categories WHERE value='actor')
AND uid IN (SELECT uid FROM categories WHERE value='musician')
But there is really nothing wrong with using HAVING ;)

MySQL Nest Join

I have a users table which contains the users information (fname, lname...etc) and a invoices table. In the invoices table I have a field called created_id which links to the user.id that created the invoice. I also have a field called staff_id which links to the staff user.id that approved the invoice.
How can I query the first and last name for both the created_id and the staff_id in a single query? Here are a few things I've tried....
SELECT
invoices.*,
users.fname as created_fname,
users.lname as created_lname
FROM
invoices
INNER JOIN users
ON users.id = invoices.created_id;
This works, but it only gets me the person's name that created the invoice. How can I add the staff's name to that as well....
SELECT
invoices.*,
users.fname as created_fname,
users.lname as created_lname,
users2.fname as staff_fname,
users2.lname as staff_lname
FROM invoices, users
LEFT JOIN
invoices,
users AS users2
ON
users.id = invoices.created_id,
users.id = users2.id
That doesn't work, but is closer. Any guidance or examples would be very helpful. Also, if you have any recommendations for good books on learning how to do more advanced MySQL queries that would be helpful too.
You need to join users table twice on table Invoice.
SELECT a.*,
b.fname created_firstName,
b.lname created_LastName,
c.fname staff_firstName,
c.lname staff_LastName
FROM Invoice a
INNER JOIN users b
ON a.created_id = b.id
INNER JOIN users c
ON a.staff_id = c.id
and best thing is you can concatenate their names into one using CONCAT
SELECT a.*,
CONCAT(b.fname, ' ', b.lname) created_fullName,
CONCAT(c.fname, ' ', c.lname) staff_fullName
FROM Invoice a
INNER JOIN users b
ON a.created_id = b.id
INNER JOIN users c
ON a.staff_id = c.id

Left Join on association table

I need help trying to join a table that uses an association table.
I have a users table
Users Table
user_id
user_name
Association Table
user_id
project_id
Project Table
project_id
project_name
I need to pull a user and the count of projects they are associated with.
SELECT u.user_name, COUNT(p.project_id) projects
FROM users u
LEFT JOIN association a ON u.user_id = a.user_id
GROUP BY u.user_name
How do I associate the two tables?
If you want to associate projects and users, you need to do 2 joins:
SELECT u.user_name, COUNT(p.project_id) projects
FROM users u
LEFT JOIN association a ON u.user_id = a.user_id
LEFT JOIN projects p ON p.project_id = a.project_id
GROUP BY u.user_name
If you want it faster you can do:
SELECT u.user_name, COUNT(a.project_id) projects
FROM users u
LEFT JOIN association a ON u.user_id = a.user_id
GROUP BY u.user_name
I think you can do something like:
SELECT
Utbl.user_name,
NumTbl.numProjects
FROM
UsersTable Utbl,
(SELECT
Atbl.user_id,
COUNT(*) AS numProjects
FROM
ProjectTable Ptbl,
AssociationTable Atbl
WHERE
Utbl.user_id = Atbl.user_id AND
Atbl.project_id = Ptbl.project_id) NumTbl
WHERE
Utbl.user_id = NumTbl.user_id

Need help with a mysql query

I have a payments table that has the following structure.
**Payments**
id
name
created_by - user_id
closed_by - user_id
**Users**
user_id
name
surname
What is the best way to show both the name and surname of the user who has created and closed the payment file.
The only way i can think this could work would be using a subquery for both(created_by,closed_by fields) thanks
Try this:
SELECT p.id, p.name,
CONCAT (u1.name,' ', u1.surname) created,
CONCAT (u2.name,' ', u2.surname) closed,
FROM payments p INNER JOIN users u1
ON p.created_by = u1.user_id
INNER JOIN users u2
ON p.closed_by = u2.user_id
EDITED: if you want name and surname splitted
SELECT p.id, p.name,
u1.name created_name, u1.surname created_surname,
u2.name closed_name, u2.surname closed_surname,
FROM payments p INNER JOIN users u1
ON p.created_by = u1.user_id
INNER JOIN users u2
ON p.closed_by = u2.user_id
A strict join is not enough, I think you can use joins in the where clause
select name, surname
from
payments p, users u
where
u.user_id = p.created_by
and u.user_id = p.closed_by
You can join to a single table multiple times, but you have to use an alias.
select
p.*,cr.*,cl.*
from
payments p
join users cr
on p.created_by = cr.user_id
join users cl
on p.closed_by = cl.user_id