Mysql LEFT JOIN из трех таблиц возвращает во многие строки - PullRequest
1 голос
/ 23 марта 2012

Я использую Mysql уже довольно давно, и меня очень смущает результат простого LEFT JOIN на трех таблицах.

У меня есть следующие три таблицы (я создал пример, чтобы сузить его)

a) персон

+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| PersonID | int(11)     | NO   | PRI | NULL    | auto_increment |
| Name     | varchar(50) | YES  |     | NULL    |                |
| Age      | int(11)     | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+

b) person_fav_artists

+----------------+--------------+------+-----+---------+----------------+
| Field          | Type         | Null | Key | Default | Extra          |
+----------------+--------------+------+-----+---------+----------------+
| FavInterpretID | int(10)      | NO   | PRI | NULL    | auto_increment |
| PersonID       | int(10)      | NO   |     | 0       |                |
| Interpret      | varchar(100) | YES  |     | NULL    |                |
+----------------+--------------+------+-----+---------+----------------+

c) person_fav_movies

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| FavMovieID | int(10)      | NO   | PRI | NULL    | auto_increment |
| PersonID   | int(10)      | NO   |     | 0       |                |
| Movie      | varchar(100) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

Мои примеры таблиц используются для хранениялюбое количество артистов и фильмов одному человеку.Погода это имеет смысл или нет, на самом деле не имеет значения, поскольку это всего лишь простой пример.

Теперь у меня есть следующие данные в таблицах:

mysql> SELECT * FROM persons;
+----------+------+------+
| PersonID | Name | Age  |
+----------+------+------+
|        1 | Jeff |   22 |
|        2 | Lisa |   15 |
|        3 | Jon  |   30 |
+----------+------+------+

mysql> SELECT * FROM person_fav_artists;
+----------------+----------+----------------+
| FavInterpretID | PersonID | Interpret      |
+----------------+----------+----------------+
|              1 |        1 | Linkin Park    |
|              2 |        1 | Muse           |
|              3 |        2 | Madonna        |
|              4 |        2 | Katy Perry     |
|              5 |        2 | Britney Spears |
|              6 |        1 | Fort Minor     |
|              7 |        1 | Jay Z          |
+----------------+----------+----------------+

mysql> SELECT * FROM person_fav_movies;
+------------+----------+-------------------+
| FavMovieID | PersonID | Movie             |
+------------+----------+-------------------+
|          1 |        1 | American Pie 1    |
|          2 |        1 | American Pie 2    |
|          3 |        1 | American Pie 3    |
|          4 |        3 | A Game of Thrones |
|          5 |        3 | Eragon            |
+------------+----------+-------------------+

Теперь я простообъединение таблиц с помощью следующего запроса:

Select * FROM persons
LEFT JOIN person_fav_artists USING (PersonID)
LEFT JOIN person_fav_movies USING (PersonID);

, который возвращает следующий результат:

+----------+------+------+----------------+----------------+------------+-------------------+
| PersonID | Name | Age  | FavInterpretID | Interpret      | FavMovieID | Movie             |
+----------+------+------+----------------+----------------+------------+-------------------+
|        1 | Jeff |   22 |              1 | Linkin Park    |          1 | American Pie 1    |
|        1 | Jeff |   22 |              1 | Linkin Park    |          2 | American Pie 2    |
|        1 | Jeff |   22 |              1 | Linkin Park    |          3 | American Pie 3    |
|        1 | Jeff |   22 |              2 | Muse           |          1 | American Pie 1    |
|        1 | Jeff |   22 |              2 | Muse           |          2 | American Pie 2    |
|        1 | Jeff |   22 |              2 | Muse           |          3 | American Pie 3    |
|        1 | Jeff |   22 |              6 | Fort Minor     |          1 | American Pie 1    |
|        1 | Jeff |   22 |              6 | Fort Minor     |          2 | American Pie 2    |
|        1 | Jeff |   22 |              6 | Fort Minor     |          3 | American Pie 3    |
|        1 | Jeff |   22 |              7 | Jay Z          |          1 | American Pie 1    |
|        1 | Jeff |   22 |              7 | Jay Z          |          2 | American Pie 2    |
|        1 | Jeff |   22 |              7 | Jay Z          |          3 | American Pie 3    |
|        2 | Lisa |   15 |              3 | Madonna        |       NULL | NULL              |
|        2 | Lisa |   15 |              4 | Katy Perry     |       NULL | NULL              |
|        2 | Lisa |   15 |              5 | Britney Spears |       NULL | NULL              |
|        3 | Jon  |   30 |           NULL | NULL           |          4 | A Game of Thrones |
|        3 | Jon  |   30 |           NULL | NULL           |          5 | Eragon            |
+----------+------+------+----------------+----------------+------------+-------------------+
17 rows in set (0.00 sec)

Пока все хорошо.Теперь у меня вопрос, является ли «нормальным» то, что «12» строк возвращаются человеку «Джефф», несмотря на тот факт, что ему назначены только четыре «художника» и три «фильма».Я думаю, что могу понять, почему результат такой, какой он есть, но я думаю, что было бы глупо возвращать так много строк для столь менее актуальных данных.

Итак, что-то не так с моим запросом или это поведениенамеренно?

Результат, который я хотел бы получить, был бы следующим (только для Джеффа):

+----------+------+------+----------------+----------------+------------+-------------------+
| PersonID | Name | Age  | FavInterpretID | Interpret      | FavMovieID | Movie             |
+----------+------+------+----------------+----------------+------------+-------------------+
|        1 | Jeff |   22 |              1 | Linkin Park    |          1 | American Pie 1    |
|        1 | Jeff |   22 |              2 | Muse           |          2 | American Pie 2    |
|        1 | Jeff |   22 |              3 | Fort Minor     |          3 | American Pie 3    |
|        1 | Jeff |   22 |              4 | Jay Z          |          1 | NULL              | <- 'American Pie 1/2/3' would be OK as well.
+----------+------+------+----------------+----------------+------------+-------------------+

Спасибо за вашу помощь!

Ответы [ 5 ]

1 голос
/ 23 марта 2012

Ничего плохого в запросе или результатах, просто возвращаются все возможные комбинации.Одним из вариантов будет разделение на два отдельных запроса, если объем данных будет большим.

0 голосов
/ 23 марта 2012

Попробуйте заменить LEFT JOIN на INNER JOIN следующим образом:

     SELECT * 
     FROM persons 
     INNER JOIN person_fav_artists USING (PersonID) 
     INNER JOIN person_fav_movies USING (PersonID); 
0 голосов
/ 23 марта 2012

Я думаю, что это нормально, так как он принимает все комбинации любимого фильма и любимого исполнителя.Я думаю, что так работает соединение.

0 голосов
/ 23 марта 2012

Вы получаете правильный результат с 12 записями, потому что это правильный кортеж с тем, как вы запрашиваете данные.Я не уверен, почему вы объединяете эти 3 таблицы, потому что по своей сути 2 связанные таблицы не относятся к одному и тому же типу данных.Я хотел бы предложить, чтобы вы выбрали человека и фильмы, а затем вы можете объединить человека и художников, потому что ваш союз будет хотеть, чтобы столбцы были одинаковыми, я бы предложил добавить тип, чтобы отличать его от художников и фильмов, и тогда хорошее имя должнопросто быть как string_value

0 голосов
/ 23 марта 2012

Такое поведение специально.

  1. Ваша первая таблица содержит 1 столбец для Джеффа.
  2. Вторая таблица имеет 4 столбца для Джеффа, поэтому объединенная таблица дает 1x4.
  3. В третьей таблице есть три столбца для Джеффа, поэтому объединенная таблица дает 1x4x3.

Теперь у вас есть все возможные комбинации.

...