Подсчет и множественная группировка в таблице MySQL «многие ко многим» - PullRequest
2 голосов
/ 22 декабря 2011

Мне интересно весь день, и я не могу это сделать.

У меня есть простая тестовая таблица с системой news в качестве примера. У нас есть news, tags и categories. News может иметь много tags и один category. Мне нужно посчитать, сколько news находится под каждым tag в каждом category. Например, у нас может быть 4 news с общим тегом в категории «политика» и 2 news с общим тегом в категории «наука».

Мои таблицы выглядят так:

news:
    - news_id
    - category_id
    - title

categories:
    - category_id
    - category_name

tags:
    - tag_id
    - tag_name

news_tags:
    - news_id
    - tag_id

Вот простая MindMap, чтобы уточнить, что мне нужно: enter image description here http://i.stack.imgur.com/6ySiJ.png

Вот запрос, который я пытался выполнить безуспешно:

SELECT *, COUNT(n.news_id) AS news_count FROM news AS n
LEFT JOIN categories AS c ON n.category_id = c.category_id
LEFT JOIN news_tags AS tn ON n.news_id = tn.news_id
LEFT JOIN tags AS t ON tn.tag_id = t.tag_id
GROUP BY t.tag_id, c.category_id;

1 Ответ

0 голосов
/ 22 декабря 2011

Ваш запрос работает без ошибок для меня.Какую ошибку вы получаете, когда запускаете запрос / Почему он не работает?

Это моя попытка настроить вашу ситуацию:

mysql> select * from news;
+---------+-------------+------------------------+
| news_id | category_ID | title                  |
+---------+-------------+------------------------+
|       1 |           1 | politics and general 1 |
|       2 |           1 | politics and general 2 |
|       3 |           1 | politics and general 3 |
|       4 |           1 | politics and general 4 |
|       5 |           2 | science and general 1  |
|       6 |           2 | science and general 2  |
|       7 |           2 | science and funny 1    |
+---------+-------------+------------------------+

mysql> select * from tags;
+--------+----------+
| tag_id | tag_name |
+--------+----------+
|      1 | general  |
|      2 | funny    |
+--------+----------+

mysql> select * from news_tags;
+---------+--------+
| news_id | tag_id |
+---------+--------+
|       1 |      1 |
|       2 |      1 |
|       3 |      1 |
|       4 |      1 |
|       5 |      1 |
|       6 |      1 |
|       7 |      2 |
+---------+--------+

mysql> select * from categories;
+-------------+---------------+
| category_id | category_name |
+-------------+---------------+
|           1 | politics      |
|           2 | science       |
+-------------+---------------+

Результат вашего запроса:

+---------+-------------+------------------------+-------------+---------------+---------+--------+--------+----------+------------+
| news_id | category_ID | title                  | category_id | category_name | news_id | tag_id | tag_id | tag_name | news_count |
+---------+-------------+------------------------+-------------+---------------+---------+--------+--------+----------+------------+
|       1 |           1 | politics and general 1 |           1 | politics      |       1 |      1 |      1 | general  |          4 |
|       5 |           2 | science and general 1  |           2 | science       |       5 |      1 |      1 | general  |          2 |
|       7 |           2 | science and funny 1    |           2 | science       |       7 |      2 |      2 | funny    |          1 |
+---------+-------------+------------------------+-------------+---------------+---------+--------+--------+----------+------------+

Однако SELECT * не имеет смысла, так как вы агрегируете счетчики по тегам / категориям, а такие вещи, как title, не имеют смысла при агрегировании.

Вы можете попробовать:

SELECT c.category_name, t.tag_name, COUNT(n.news_id) AS news_count FROM news AS n
LEFT JOIN categories AS c ON n.category_id = c.category_id
LEFT JOIN news_tags AS tn ON n.news_id = tn.news_id
LEFT JOIN tags AS t ON tn.tag_id = t.tag_id
GROUP BY t.tag_id, c.category_id;

Получить:

+---------------+----------+------------+
| category_name | tag_name | news_count |
+---------------+----------+------------+
| politics      | general  |          4 |
| science       | general  |          2 |
| science       | funny    |          1 |
+---------------+----------+------------+
...