Two left joins and a union in MySQL - sql

I'm trying to do a pretty complex query in MySQL; complex for me, at least.
Here's an example of what I'm trying to do:
SELECT * FROM friends
LEFT JOIN users ON users.uid = friends.fid1
LEFT JOIN users ON users.uid = friends.fid2
WHERE (friends.fid1 = 1) AND (friends.fid2 > 1)
UNION SELECT fid2 FROM friends
WHERE (friends.fid2 = 1) AND (friends.fid1 < 1)
ORDER BY RAND()
LIMIT 6;
I'm getting back: ERROR 1066 (42000): Not unique table/alias: 'users'.
Where am I going wrong, and how should I really be performing this query?

Alias your table, like:
LEFT JOIN users u1 ON u1.uid = friends.fid1
LEFT JOIN users u2 ON u2.uid = friends.fid2

You have written left join two times with different fields of tables, it seems to When it got parse so give them alias and then join them with friends Table
LEFT JOIN users users1 ON users1.uid = friends.fid1
LEFT JOIN users users2 ON users2.uid = friends.fid2

Related

SQL Where on different table

SELECT * FROM student_mentor sm INNER JOIN users u
ON sm.student_id = u.user_id
WHERE sm.teacher_id = $teacher_id
Teacher_id being the session id,
I want to see all the students that have the same mentor.
Right now if I run this I just see all of the students twice, maybe one of you knows why?
My db scheme
You are not specifying on which columns you want to do the join, so you're getting a cross reference where all records are joined to all records.
You should do something like (not sure about your column names):
SELECT * FROM student_mentor sm INNER JOIN users u
ON sm.student_id = u.user_id
WHERE sm.teacher_id = $teacher_id

Query shows each row twice

It shows each row twice... I wrote it to pick some rows from different tables, it shows what I want but it shows those rows twice, each. why ?
SELECT
tbluser.fullname, tbluser.email, tblJobAdv.advtitle, tblPersonalInfo.country,
tblPersonalInfo.city, tblJobOffer.digitalsignature
FROM
tblUser
LEFT JOIN
tblPersonalInfo ON tblUser.userid = tblPersonalInfo.userid
LEFT JOIN
tblApplication ON tblApplication.userid = tblUser.userid
LEFT JOIN
tblJobAdv ON tblJobAdv.advid = tblApplication.advid
LEFT JOIN
tblJobOffer ON tblUser.userid = tblJobOffer.userid
WHERE
tblJobAdv.userId IN (SELECT userid FROM tblUser WHERE email = 'h#y.com')
It shows duplicate records because you are joining along different dimensions. If I had to guess, based on the table names, users are applying for multiple jobs.
A quick and easy fix is to do select distinct.
Actually, you should check your underlying tables to be sure there are no duplicates in them. I am suspicious about the Application table. I think there might be multiple applications for a given user.
using 'group by' or 'distinct' makes your query slow and inefficient.
I think you would better finding duplicated rows from other tables like tblJobAdv,
and give some more 'where condition' to those tables.
SELECT tbluser.fullname, tbluser.email, tblJobAdv.advtitle, tblPersonalInfo.country,
tblPersonalInfo.city, tblJobOffer.digitalsignature
FROM
tblUser
LEFT JOIN
tblPersonalInfo ON tblUser.userid = tblPersonalInfo.userid
LEFT JOIN
tblApplication ON tblApplication.userid = tblUser.userid
LEFT JOIN
tblJobAdv
ON tblJobAdv.advid = tblApplication.advid
AND tblJobAdv.isUsable = 'Usable' /* some more where condition example */
LEFT JOIN
tblJobOffer ON tblUser.userid = tblJobOffer.userid
WHERE
tblJobAdv.userId IN (SELECT userid FROM tblUser WHERE email = 'h#y.com')
Please try select distinct to avoid duplicate records
You just need to group the records or distinct will do (remove duplicates),
Select distinct tbluser.fullname, tbluser.email, tblJobAdv.advtitle, tblPersonalInfo.country,
tblPersonalInfo.city, tblJobOffer.digitalsignature
from tblUser
left join tblPersonalInfo
ON tblUser.userid = tblPersonalInfo.userid
left join tblApplication
On tblApplication.userid = tblUser.userid
left join tblJobAdv
On tblJobAdv.advid = tblApplication.advid
left join tblJobOffer
On tblUser.userid = tblJobOffer.userid
where tblJobAdv.userId IN (select userid from tblUser where email = 'h#y.com')

SQL Query - Multiple Joins on Same field

I need assistance building this query where i need to select different values from same table but different Unique Keys.
To elaborate more ill provide the below example:
I have 2 tables:
Issues (IssueID, AuthorID_FK, AssigedID_FK, ... )
Users (UserID, User_Label, ... )
Both AuthorID_FK & AssigedID_FK are linked to table Users and i need to get in the same query result the User_Label for both.
Can you please assist?
Thanks,
SELECT a.IssueID, b.User_Label, c.User_Label FROM Issues a
INNER JOIN USERS b on a.AuthorID_FK = b.UserID
INNER JOIN USERS c on a.AssignedID_FK = c.UserID
something like that :) This should work in MS SQL Server
Well, this one should work too :)
SELECT IssueID, U.User_Label FROM Issues I
INNER JOIN Users U ON U.UserID = I.AuthorID_FK
UNION
SELECT IssueID, U.User_Label FROM Issues I
INNER JOIN Users U ON U.UserID = I.AssigedID_FK
Wont
SELECT a.IssueID, b.UserID
FROM Issues a
JOIN Users b ON (a.AuthorID_FK=b.UserID OR a.AssignedID_FK = b.UserID)
work?
You may want to try something like this
SELECT
issues.IssueID,
Authour.User_Label AS Author_Label,
Assigned.User_Label AS Assigned_user_Label
FROM
issues
INNER JOIN users AS Authour ON Authour.UserID = issues.AuthorID_FK
INNER JOIN users AS Assigned ON Assigned.UserID = issues.AssignedID_FK

MySQL JOIN / GROUP_CONCAT second table?

So I have this query that works perfectly:
SELECT users.*,
GROUP_CONCAT(categories.category_name) AS categories
FROM users
LEFT OUTER JOIN user_categories ON users.user_id = user_categories.user_id
LEFT OUTER JOIN categories ON user_categories.category_id = categories.category_id
WHERE users.user_city = 'brooklyn'
GROUP BY users.user_id
LIMIT 10;
Say I have another table that holds phone numbers, for the "users" a user can have any number of phone numbers... How would I go about doing round about the exact same thing I am doing wit the categories? In other words, I would like to get another column with ALL of the phone_numbers found in the "phones" table that have the same "user_id" and concat them together(phone1, phone2, phone3)? I have tried:
SELECT users.*,
GROUP_CONCAT(phones.phone_number) AS phone_numbers,
GROUP_CONCAT(categories.category_name) AS categories
FROM users
LEFT OUTER JOIN phones ON users.user_id = phones.user_id
LEFT OUTER JOIN user_categories ON users.user_id = user_categories.user_id
LEFT OUTER JOIN categories ON user_categories.category_id = categories.category_id
WHERE users.user_city = 'brooklyn'
GROUP BY users.user_id
LIMIT 10;
With no luck... or at least the query executes but it does some weird duplication thing... any help would be awesome!
Thanks!
It does weird things, becaue there is a cross product of certain rows. You can use the DISTINCT keyword to get only unique phone numbers:
GROUP_CONCAT(DISTINCT phones.phone_number) AS phone_numbers,
Check the documentation. Alternatively, you can get the phone numbers in another query where you would select only the phone numbers with a condition like WHERE phones.user_id IN (x, x, x, ...) (x are IDs returned from the first query).
This happened to me, I later had to alter my query to this.
SELECT
( SELECT GROUP_CONCAT(`partnumber`) FROM `product_partnumber` AS `n` WHERE `p`.`id`=`n`.`product_id`) as `partnumbers`,
( SELECT GROUP_CONCAT(`oem`) FROM `product_oem` AS `n` WHERE `p`.`id`=`n`.`product_id`) as `oems`
FROM `product` AS `p`
So I had to use sub queries else I had the duplication.

joining one table multiple times to other tables

I have three tables:
Table User( userid username)
Table Key( userid keyid)
Table Laptop( userid laptopid)
i want all users who have either a key or a laptop, or both. How do i write the query so that it uses a join between table User and table Key, as well as a join between table User and table Laptop?
The main problem is that in the actual scenario, there are twelve or so table joins, sth like:
" select .. From a left join b on (...), c join d on (..),e,f,g where ...",
and i see that a could be joined to b, and a could also be joined to f. So assuming i can't make the tables a,b, and f appear side-by-side, how do i write the sql query?
You can use multiple joins to combine multiple tables:
select *
from user u
left join key k on u.userid = k.userid
left join laptop l on l.userid = u.userid
A "left join" also finds users which do not have a key or a laptop. If you replace both with "inner join", it would find only users with a laptop and a key.
When a "left join" does not find a row, it will return NULL in its fields. So you can select all users that have either a laptop or a key like this:
select *
from user u
left join key k on u.userid = k.userid
left join laptop l on l.userid = u.userid
where k.userid is not null or l.userid is not null
NULL is special, in that you compare it like "field is not null" instead of "field <> null".
Added after your comment: say you have a table Mouse, that is related to Laptop, but not to User. You can join that like:
select *
from user u
left join laptop l on l.userid = u.userid
left join mouse m on m.laptopid = l.laptopid
If this does not answer your question, you gotta clarify it some more.
select distinct u.userid, u.username
from User u
left outer join Key /* k on u.userid = k.userid */
left outer join Laptop /* l on u.userid = l.userid */
where k.userid is not null or l.userid is not null
EDIT
"The main problem is that in the actual scenario, there are twelve or so table joins, sth like:
" select .. From a left join b on (...), c join d on (..),e,f,g where ...",
and i see that a could be joined to b, and a could also be joined to f. So assuming i can't make the tables a,b, and f appear side-by-side, how do i write the sql query?"
You can have as many left outer joins as required. Join the table with the primary key to the rest of the tables or on any other field where field values of one table should match field values of other table.
eg will explain better than words
select *
from a
left outer join b on a.pk = b.fk -- a pk should match b fk
left outer join c on a.pk = c.fk -- a pk should match c fk
left outer join d on c.pk = d.fk -- c pk should match d fk
and so on
-- // Assuming that a user can have at max 1 items of each type
SELECT u.*
-- // Assuming that a user can have more then 1 items of each type, just add DISTINCT:
-- // SELECT DISTINCT u.*
FROM "User" u
LEFT JOIN "Key" u1 ON u.UserID = u1.UserID
LEFT JOIN "Laptop" u2 ON u.UserID = u2.UserID
LEFT JOIN "Server" u3 ON u.UserID = u3.UserID
-- // ...
WHERE COALESCE(u1.UserID, u2.UserID, u3.UserID /*,...*/) IS NOT NULL
As you described the case, you only wanted to know if someone has a laptop or a key. I would write the query with a subquery rather than a join:
select *
from user
where userid in (select userid from key union select userid from laptop)
The reason for this is that by a join a person with multiple laptops or multiple keys will be listed several times (unless you use distinct). And even you use distinct you end up with a less efficient query (at least on Oracle the query optimizer doesn't appear to be able to create an efficient plan).
[Edited to correct what Rashmi Pandit pointed out.]
Solution one:
SELECT * FROM [User] u
INNER JOIN [Key] k
ON u.userid = k.userid
UNION
SELECT * FROM [User] u
INNER JOIN Laptop l
ON u.userid = l.userid
[...]
Solution two:
SELECT * FROM [User] u
LEFT JOIN [Key] k
ON u.userid = k.userid
LEFT JOIN Laptop l
ON u.userid = l.userid
LEFT JOIN [...]
WHERE k.userid IS NOT NULL
OR l.userid IS NOT NULL
OR [...]
Just a guess, also you could check the execution plan for theses two to see if the UNION one is heavier or vice versa.
SELECT *
FROM User
LEFT JOIN Key ON User.id = Key.user_id
LEFT JOIN Laptop ON User.id = Laptop.user_id
WHERE Key.id IS NOT NULL OR Laptop.id IS NOT NULL