Получить общее количество связанных записей по нескольким таблицам MySQL - PullRequest
0 голосов
/ 07 октября 2011

У меня следующий запрос, объединяющий две таблицы, которые содержат теги, связанные с двумя отдельными объектами: cat и dog.Я пытаюсь создать таблицу, в которой перечислены теги и количество их появления в двух таблицах.Это нормализованная система тегов, поэтому в таблицах cat_tags и dog_tags указаны только идентификаторы тегов, и поэтому я делаю еще одно INNER JOIN для получения фактического значения тега.

SELECT x.tag_id, (COUNT(y.tag_id) + COUNT(z.tag_id)) AS num, tag_name AS tag
FROM (SELECT dt.tag_id FROM dog_tags dt UNION SELECT st.tag_id FROM cat_tags st) x
LEFT JOIN dog_tags y ON y.tag_id = x.tag_id
LEFT JOIN cat_tags z ON z.tag_id = x.tag_id
INNER JOIN tags t ON x.tag_id = t.tag_id
GROUP BY x.tag_id ORDER BY num DESC LIMIT 0,100

Проблема в том, чточисла num не верны для тегов, которые появляются несколько раз в двух таблицах.Например, идентификатор тега номер 5 («ошейник») появляется дважды в cat_tags и дважды в dog_tags, однако в приведенном выше запросе общее число равно 8 вместо 4. Другой тег, который появляется три раза, получается как 6. Что-то умножает их на2. Что это?

Ответы [ 2 ]

0 голосов
/ 07 октября 2011

Я думаю, что ваш запрос действительно сложный, и вы можете попробовать что-то вроде этого:

  SELECT tag_id
       , tag_name
       , sum(num) as num
    FROM tags
    join
      (
          SELECT tag_id, count(*) as num FROM dog_tags GROUP BY tag_id
          union all
          SELECT tag_id, count(*) as num FROM cat_tags GROUP BY tag_id
      ) as AnimalsCount on AnimalsCount.tag_id = tags.tag_id
GROUP BY tag_id
       , tag_name -- you can remove this if you are 100% sure is not necessary

Кстати, проверьте разницу между union и union all: http://dev.mysql.com/doc/refman/5.0/en/union.html.

0 голосов
/ 07 октября 2011

Попробуйте:

select t.tag_id, t.tag_name as tag,
    ifnull(dc.dog_total, 0) + ifnull(cc.cat_total, 0) as num
from
    tags t
    left join (
        select tag_id, count(*) as dog_total
        from dog_tags
        group by tag_id
    ) as dc on t.tag_id = dc.tag_id
    left join (
        select tag_id, count(*) as cat_total
        from cat_tags
        group by tag_id
    ) as cc on t.tag_id = cc.tag_id
order by num desc
limit 0, 100

Что ж, проблема заключалась в том, что у вас есть объединения в вашем запросе.Потому что вы не группировали по tag_id для каждой исходной таблицы.Таким образом, если collar появилось 2 раза в dog_tags и 3 в cat_tags, объединение привело бы к 6 строкам с одинаковым tag_id, поэтому счет был бы неправильным.Помните, что объединение - это декартово произведение строк каждой объединенной таблицы с определенными критериями.Таким образом, группируя сначала по tag_id для каждой исходной таблицы, мы гарантируем, что tag_id появляется только один раз в каждой таблице или производной таблице .И когда мы объединяем таблицы, каждый tag_id будет выдавать одну строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...