Вот что происходит. Рассмотрим запрос по частям и то, что MySQL обрабатывает в процессе работы.
Сначала вы выбираете из пунктов (select i.item_id, i.item_name, avg(ir.rating) from Items i
):
+---------+-----------+
| item_id | item_name |
+---------+-----------+
| 1 | Item 1 |
| 2 | Item 2 |
| 3 | Item 3 |
| 4 | Item 4 |
| 5 | Item 5 |
+---------+-----------+
Тогда вам остается присоединиться к рейтингам (left join ItemRating ir ON ir.item_id = i.item_id
). Обратите внимание, что Элемент 1 появляется в двух строках после объединения, потому что именно так JOIN определен для работы - он возвращает одну строку для каждого совпадения условия соединения (и LEFT в основном означает «вернуть каждую строку в первой таблице хотя бы один раз, даже если в этой строке нет совпадений с условиями соединения»).
+---------+-----------+-----------+------------+
| item_id | item_name | ir.rating | ir.item_id |
+---------+-----------+-----------+------------+
| 1 | Item 1 | 9 | 1 |
| 1 | Item 1 | 6 | 1 |
| 2 | Item 2 | NULL | NULL |
| 3 | Item 3 | 10 | 3 |
| 4 | Item 4 | NULL | NULL |
| 5 | Item 5 | NULL | NULL |
+---------+-----------+-----------+------------+
Наконец, вы группируете по рейтингу (group by ir.item_id
). Это вернет одну строку для каждого уникального ir.item_id. Существует три уникальных ir.item_ids (как вы можете видеть в последнем столбце): 1
, NULL
и 3
. Для каждого из них возвращается одна строка и усредняется рейтинг.
Итак, для 1
имеем:
+---------+-----------+-----------+------------+
| item_id | item_name | ir.rating | ir.item_id |
+---------+-----------+-----------+------------+
| 1 | Item 1 | 9 | 1 |
| 1 | Item 1 | 6 | 1 |
+---------+-----------+-----------+------------+
Который сворачивается в:
+---------+-----------+----------------+------------+
| item_id | item_name | avg(ir.rating) | ir.item_id |
+---------+-----------+----------------+------------+
| 1 | Item 1 | 7.5 | 1 |
+---------+-----------+----------------+------------+
Для NULL
имеем:
+---------+-----------+-----------+------------+
| item_id | item_name | ir.rating | ir.item_id |
+---------+-----------+-----------+------------+
| 2 | Item 2 | NULL | NULL |
| 4 | Item 4 | NULL | NULL |
| 5 | Item 5 | NULL | NULL |
+---------+-----------+-----------+------------+
Который сворачивается в:
+---------+-----------+----------------+------------+
| item_id | item_name | avg(ir.rating) | ir.item_id |
+---------+-----------+----------------+------------+
| 2| Item 2 | NULL | NULL |
+---------+-----------+----------------+------------+
Для 3
имеем:
+---------+-----------+-----------+------------+
| item_id | item_name | ir.rating | ir.item_id |
+---------+-----------+-----------+------------+
| 3 | Item 3 | 10 | 3 |
+---------+-----------+-----------+------------+
Который сворачивается в:
+---------+-----------+----------------+------------+
| item_id | item_name | avg(ir.rating) | ir.item_id |
+---------+-----------+----------------+------------+
| 3 | Item 3 | 10 | 3 |
+---------+-----------+----------------+------------+
Объединение трех свернутых результатов дает:
+---------+-----------+----------------+------------+
| item_id | item_name | avg(ir.rating) | ir.item_id |
+---------+-----------+----------------+------------+
| 1 | Item 1 | 7.5 | 1 |
| 3 | Item 3 | 10 | 3 |
| 2 | Item 2 | NULL | NULL |
+---------+-----------+----------------+------------+
Что у тебя есть.
Одна сложная часть - способ, которым свернуты строки NULL. Напомним, это были нулевые строки:
+---------+-----------+-----------+------------+
| item_id | item_name | ir.rating | ir.item_id |
+---------+-----------+-----------+------------+
| 2 | Item 2 | NULL | NULL |
| 4 | Item 4 | NULL | NULL |
| 5 | Item 5 | NULL | NULL |
+---------+-----------+-----------+------------+
Когда вы группируете, большинство систем баз данных даже не позволяют выбирать столбцы, которые не являются частью группы. MySQL является исключением. Так как вы группируете только по ir.rating, это единственный, который больше всего позволит вам выбрать, потому что не существует четкого способа свернуть три строки неагрегированным способом. MySQL просто выбирает первое, с которым сталкивается, и использует значения в этой строке в качестве свернутого значения. Итак (2,4,5) => (2) и (пункт 2, пункт 4, пункт 5) => пункт 2 и (NULL, NULL, NULL) => NULL. Вот почему вы видите только строку 2 (на самом деле вы видите три свернутые строки, которые выглядят как строка 2).
Чтобы действительно увидеть это в действии и понять, рассмотрите этот запрос:
select group_concat(i.item_id), group_concat(i.item_name), avg(ir.rating) from Items i left join ItemRating ir ON ir.item_id = i.item_id group by ir.item_id;
Это похоже на исходный запрос, за исключением того, что все три выбранных столбца теперь имеют функции группирования. Я использую GROUP_CONCAT
, который просто объединяет строки для формирования свернутой версии (это было бы допустимо в других системах SQL, кроме MySQL). Это возвращает это:
+-------------------------+---------------------------+----------------+
| group_concat(i.item_id) | group_concat(i.item_name) | avg(ir.rating) |
+-------------------------+---------------------------+----------------+
| 2,4,5 | Item 2,Item 4,Item 5 | NULL |
| 1,1 | Item 1,Item 1 | 7.5000 |
| 3 | Item 3 | 10.0000 |
+-------------------------+---------------------------+----------------+