简体   繁体   中英

MySQL many-to-many JOIN returning duplicates

I have two three tables. users , jobs and users_jobs . One user can have many jobs and one job can have many users.

Here is my users table:

+----+------+--------+
| ID | Name | gender |
+----+------+--------+
|  1 | Bob  |   male |
|  2 | Sara | female |
+----+------+--------+

my jobs table:

+----+----------+
| id |  job_id  |
+----+----------+
|  1 | Engineer |
|  2 | Plumber  |
|  3 | Doctor   |
+----+----------+

users_jobs table:

+---------+--------+
| user_id | job_id |
+---------+--------+
|       1 |      1 |
|       1 |      2 |
|       1 |      3 |
|       2 |      1 |
+---------+--------+

As an example, i want to select all males and check if they have at least 1 job and then return their info. If they have no jobs, then don't select/return that user. This is my query:

SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'

But it returns Bob's info 3 times since he has 3 jobs. I don't want duplicates, how can I get rid of duplicates without using DISTINCT or GROUP BY since performance is very important here.

Thank you!

MySQL allows you to do one a little odd thing, you can select more columns than what's in the GROUP BY clause and aggregate functions (this is not allowed in most other SQL engines). While this sometimes can produce unexpected results, it can work if you don't select data which can appear in multiple rows in the resulting query.

So, for your question - the query WILL return multiple rows for the same user, as some of them have many jobs (busy life, huh?). You generally can't get all their jobs in a single row, as each row is the user's data + their jobs - that's what we JOIN on. But that's not entirely true - you can use GROUP BY and GROUP_CONCAT() to concat all the other data into a single string. I wouldn't generally recommend it, but if its what you need...

SELECT u.Name, GROUP_CONCAT(j.job_id SEPARATOR ', ') as jobs
FROM users u
JOIN users_jobs uj
  ON u.ID = uj.user_id
JOIN jobs j 
  ON j.id = uj.job_id
GROUP BY u.ID

This would return

Name    | jobs
--------+-------------------------------
Bob     | Engineer, Plumber, Doctor
Sara    | Engineer

If you only want males, add in the where clause,

SELECT u.Name, GROUP_CONCAT(j.job_id SEPARATOR ', ') as jobs
FROM users u
JOIN users_jobs uj
  ON u.ID = uj.user_id
JOIN jobs j 
  ON j.id = uj.job_id`
WHERE u.gender = 'male'
GROUP BY u.ID

See live fiddle at http://sqlfiddle.com/#!9/df0afe/2

For this it may will help you, You can use " Limit " keyword to limit the amount of records fetched

"SELECT * FROM users
        INNER JOIN users_jobs
        ON users_jobs.user_id = users.id
        WHERE users.gender = 'male'" limit 1;

        May this will help you!
        Thanks!

To follow on from the comments, for performance, it's necessary to use a distinct in your query, try:

SELECT DISTINCT Name FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'

If you're looking to get all the columns but keep the id's distinct you can use a GROUP BY , try:

SELECT * FROM users
INNER JOIN users_jobs
ON users_jobs.user_id = users.id
WHERE users.gender = 'male'
GROUP BY users.id

Although this will also effect performance, it depends on what you prioritize the most.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM