Joining multiple columns from table a to one on table b - mysql

I've spent a bit of time researching this on here and the mysql site but I'm a bit confused on two things: which sort of join to use and how (or if) to use an alias.
The query:
SELECT forum_threads.id, forum_threads.forum_id, forum_threads.sticky,
forum_threads.vis_rank, forum_threads.locked, forum_threads.lock_rank,
forum_threads.author_id, forum_threads.thread_title, forum_threads.post_time,
forum_threads.views, forum_threads.replies, users.username AS author_username
FROM forum_threads LEFT JOIN users ON forum_threads.author_id = users.id
WHERE forum_threads.forum_id=XXX
Now that query currently finds all threads from the given forum and joins the threads author id to the username table. I also have lastpostid which I'd also like to include in that query and join again on the users table so I can get the username for the last poster too.
I tried adding:
LEFT JOIN users ON threads.lastpostid = users.username
but that just results in an alias error as users isn't unique.
I also tried using both an alias on the main query and on the second join but it keeps giving me missing field errors.
Could someone give me a point in right direction please?

Yes, you need a different alias each time. Every time you refer to the table in the query you should use the approprate alias.
SELECT
forum_threads.id,
-- etc...,
forum_threads.replies,
u1.username AS author_username
u2.username AS last_post_username
FROM forum_threads
LEFT JOIN users u1 ON forum_threads.author_id = u1.id
LEFT JOIN users u2 ON threads.lastpostid = u2.username
WHERE forum_threads.forum_id=XXX

Related

mySQL JOIN same table with specific columns

I need to fetch all entries from a table titled users and JOIN a user from the same table based on a userID in the original users entry . I have a simple JOIN query that completes this requirement but I only want to return two columns (userID and fullName) during the JOIN. Currently I'm returning the whole user entry from the JOIN and obviously the column names overlap. For our application's purposes, I need to rename the columns returned from the JOIN. I'm currently using the query below.
SELECT * FROM users u1
JOIN users AS u2
ON(u1.dealer = u2.userID)
This seems like it should be relatively simple but I can't seem to figure it out. I've searched for hours but haven't found a clear solution.
SELECT u1.userID as userID,u1.fullName as fullName,
u2.userID as dealeruserID,u2.fullName as dealerfullName
FROM users u1 JOIN users AS u2 ON(u1.dealer = u2.userID)
I am assuming you need user data and their corresponding Dealers.
Just a thought - for the dealer users - what is their value of "dealer" ?
With the help from Simone I was able to modify her answer to fit my use case.
SELECT u1.*,
u2.userID as dealeruserID,
u2.fullName as dealerfullName
FROM users u1
JOIN users AS u2 ON(u1.dealer = u2.userID)

SQL matching IDs from different columns with their respective username

I have a table containing the columns user_id and lastreply_by_user_id and I'm looking for a way to match their columns with their username from the user table with id.
SELECT
table_threads.*,
table_users.username
FROM
threads AS table_threads
INNER JOIN users as table_users ON table_threads.user_id = table_users.id
OR table_threads.lastreply_by_user_id = table_users.id
WHERE
table_threads.category_id = :category_id
This is the code I have right now but this at the moment creates duplicate entries instead of one merged.
Just started with SQL recently and found the JOIN commands maybe it isn't the right one just point me in the right direction and I'll be thankful.
You need two joins to the same user table for that: one to connect by user_id, and one more to connect by lastreply_by_user_id. Use table aliases for disambiguation:
SELECT
t.*,
u.username as user_name,
r.username as last_reply_name
FROM
threads AS t
INNER JOIN users as u ON t.user_id = u.id -- actual user
INNER JOIN users as r ON t.lastreply_by_user_id = r.id -- reply user
WHERE
table_threads.category_id = :category_id

What is the best way to implement a sql for retrieving multiple user names from same query?

I have a products table where I include 3 columns, created_user_id, updated_user_id and in_charge_user_id, all of which are related to my user table, where I store the id and name of the users.
I want to build an efficient query to obtain the names of the corresponding user_id's.
The query that I build so far is the following:
SELECT products.*,
(SELECT name FROM user WHERE user_id = products.created_user_id) as created_user,
(SELECT name FROM user WHERE user_id = products.updated_user_id) as updated_user,
(SELECT name FROM user WHERE user_id = products.in_charge_user_id) as in_charge_user
FROM products
The problem with this query is that if I have 30,000 records, I am executing 3 more queries per row.
What would be a more efficient way of achieving this? I am using mysql.
For each type of user id (created, updated, in_charge) you would JOIN the users table once:
SELECT
products.*,
u1.username AS created_username,
u2.username AS updated_username,,
u3.username AS in_charge_username,
FROM products
JOIN user u1 ON products.created_user_id = u1.user_id
JOIN user u2 ON products.updated_user_id = u2.user_id
LEFT JOIN user u3 ON products.in_charge_user_id = u3.user_id
This is the best practice method to obtain the data.
It is similiar to your query with sub-selects but a more modern approach which I think the database can optimize and utilize better.
Important:
You need foreign key index on all the user_id fields in both tables!
Then the query will be very fast no matter how many rows are in the table. This requires an engine which supports foreign keys, like InnoDB.
LEFT JOIN or INNER JOIN ?
As the other answers suggest a LEFT JOIN, I would not do a left join.
If you have an user id in the products table, there MUST be a linked user_id in the user table, except for the in_charge_user which is only present some times. If not, the data would be semantically corrupt. The foreign keys assure that you always have a linked user_id and a user_id can only be deleted when there is no linked product left.
JOIN is equivalent to INNER JOIN.
You can use LEFT JOIN instead of subselects.
Your query should be like:
SELECT
P.*,
[CU].[name],
[UU].[name],
[CU].[name]
FROM products AS [P]
LEFT JOIN user AS [CU] ON [CU].[user_id] = [P].[created_user_id]
LEFT JOIN user AS [UU] ON [UU].[user_id] = [P].[updated_user_id]
LEFT JOIN user AS [CU] ON [CU].[user_id] = [P].[in_charge_user_id]
First, your query should be fine. You only need an index on user(user_id) or better yet user(user_id, name) for performance. I imagine that the first exists.
Second, you can write this using LEFT JOIN:
SELECT p.*, uc.name as created_user,
uu.name as updated_user, uin.name as in_charge_user
FROM products p LEFT JOIN
user uc
ON uc.user_id = p.created_user_id LEFT JOIN
user uu
ON uu.user_id = p.updated_user_id LEFT JOIN
user uin
ON uin.user_id = p.in_charge_user_id;
With one of the above indexes, the two methods should have very similar performance.
Also note the use of LEFT JOIN. This handles the case where one or more of the user ids is missing.
Try this below query
SELECT products.*, c.name as created_user,u.name as updated_user,i.name as in_charge_user
FROM products left join user c on(products.created_user_id=c.user_id ) left join user u on(products.updated_user_id=u.user_id ) left join user u on(products.in_charge_user_id=i.user_id )
Also as Gordon Linoff mentioned create index on user table will fetch your data faster.

MySQL saying that column is ambiguous

I need to do a query on the same field on a MySQL table but with different parameters. This is my query. The issue that comes up is that MySQL is saying that users_name is ambiguous.
SELECT projects_id,
projects_users_id,projects_companies_id,projects_name,
projects_description,project_registered_date,
projects_users_id_register,
users.users_name as userInCharge,companies.companies_name as company,
users.users_name as user_register FROM projects
LEFT JOIN users as userInCharge ON (users_id = projects_users_id)
LEFT JOIN users as register ON (users_id=projects_users_id_register)
LEFT JOIN companies ON (companies_id = projects_companies_id) ORDER BY projects_id DESC
My goal is to get the ID of both the person in charge of the project and the person who registered the project. How do I do this?
Your ambiguity is arising because of these LEFT JOIN clauses:
LEFT JOIN users as userInCharge ON (users_id = projects_users_id)
LEFT JOIN users as register ON (users_id=projects_users_id_register)
You need to specify where users_id is coming from (yes - I know they're from the same table, but SQL is a bit slow sometimes) Try:
LEFT JOIN users as userInCharge ON (userInCharge.users_id = projects_users_id)
LEFT JOIN users as register ON (register.users_id=projects_users_id_register)
Use the table alias and not users.users_name.
And also in the joins.
You JOIN with users table as userInCharge and register so use these names when You specify columns
userInCharge.users_name as userInCharge
register.users_name as user_register
instead of
users.users_name as userInCharge
users.users_name as user_register

Mysql query incredibly slow in LEFT JOIN if the given value 0 to the primary id

In this sql:
SELECT s.*,
u.id,
u.name
FROM shops s
LEFT JOIN users u ON u.id = s.user_id
OR u.id = s.owner_user_id
WHERE s.status = 1
For some reason this query takes an amazing time. although id is the primary key. it seems especially after I added this part OR u.id=s.owner_user_id the query became slow. owner_user_id often is 0 only handful of times. But why would it take so long apparently scanning the whole table? The database table users is very long and big. I didn't design it. this is for a client who subsequent programmers added too many fields. the table is 22k rows and dozens of fields.
*the names of the fields for demonstration only. actual names are different, so don't ask me why I'm looking for owner_user_id (; I did solve the slowness by remove the "OR ..." part and instead searching for the id in the loop if it is not 0. but I would like to know why this is happening and how to speedup that query as is.
You may be able to speed it up by using IN instead of the OR but that is minor.
SELECT u.id,
u.name
FROM shops s
LEFT JOIN users u ON u.id IN ( s.user_id, s.owner_user_id )
WHERE s.status = 1
Firstly, are there any indexes on this table? Mainly one on the user.id field or the s.user_id or s.owner_user_id?
However, I must ask why you need to use a LEFT JOIN instead of a regular join. The LEFT JOIN causes the matching of every row with every other one. And since I'm assuming the value / id should either be in the user_id or the owner_user_id field, and that there will always be a match, if that is the case then the use of a JOIN should speed the query up a bit.
And as Mitch said, 22k rows is tiny.
How are you going to know which user record is which? Here's how I'd do it
SELECT s.*,
u.name AS user_name,
o.name AS owner_name
FROM shops s
LEFT JOIN users u ON s.user_id = u.id
LEFT JOIN users o ON s.owner_user_id = o.id
WHERE s.status = 1
I've omitted the IDs from the user table in the SELECT as these will be part of s.* anyway.
I'm curious about the left joins too. If shops.user_id and shops.owner_user_id are required foreign keys, use inner joins instead.