获取多个MySQL表中的总相关记录数

时间:2011-10-07 18:18:02

标签: mysql union left-join inner-join

我有以下查询,UNIONs两个表包含与两个独立实体相关联的标签:cat和dog。我正在尝试创建一个表,列出标签及其在两个表中出现的次数。这是一个规范化的标记系统,因此在cat_tags和dog_tags表中只引用了标记ID,这就是为什么我要进行另一个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计数不正确。例如,标签ID号5(“领子”)在cat_tags中出现两次,在dog_tags中出现两次,但是上面的查询给出的总计数为8而不是4.另一个出现三次的标签出现为6.有些东西乘以它们这是什么?

2 个答案:

答案 0 :(得分:0)

试试这个:

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分组。因此,如果collardog_tags中出现2次,在cat_tags中出现3次,则联接将导致6行共享相同的tag_id,因此计数将是错误的。请记住,连接是具有特定条件的每个连接表的行的笛卡尔积。因此,通过为每个源表首先按tag_id进行分组,我们确保tag_id仅在每个表或派生表中出现一次。当我们加入表时,每个tag_id将产生一行。

答案 1 :(得分:0)

我认为您的查询非常复杂,您可以尝试这样的事情:

  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

BTW检查unionunion all之间的区别:http://dev.mysql.com/doc/refman/5.0/en/union.html