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

发布于 2024-12-08 17:48:16 字数 652 浏览 1 评论 0原文

我有以下查询,联合两个表,其中包含与两个单独实体关联的标签:猫和狗。我正在尝试创建一个表格,列出标签及其在两个表格中出现的次数。这是一个规范化的标记系统,因此 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

问题在于,对于在两个表中多次出现的标签,计数不正确。例如,标签 ID 号 5(“领子”)在 cat_tags 中出现两次,在dog_tags 中出现两次,但是上述查询给出的总计数为 8,而不是 4。另一个出现 3 次的标签则为 6。将它们乘以2. 它是什么?

I have the following query that UNIONs two tables which contains tags associated with two separate entities: cat and dog. I am trying to create a table that lists tags and the number of times their appear across two tables. This is a normalized tagging system, so only the tag ID is referenced in the cat_tags and dog_tags tables, and that's why I am doing another INNER JOIN to get the actual tag value.

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

The problem is that the num counts are not correct for tags that appear multiple times across the two tables. For example tag ID number 5 ("collar") appears twice in cat_tags and twice in dog_tags, however the above query gives the total count as 8 instead of 4. Another tag that appears three times comes out as 6. Something is multiplying them by 2. What is it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦回梦里 2024-12-15 17:48:17

试试这个:

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< /code>,所以计数是错误的。请记住,联接是每个联接表的行与特定条件的笛卡尔积。因此,通过首先按每个源表的 tag_id 进行分组,我们可以确保 tag_id 在每个表或派生表中仅出现一次。当我们连接表时,每个 tag_id 将生成一行。

Try this:

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

Well, the problem was the joins you have in your query. Because you weren't grouping by tag_id for each source table. So, if collar appeared 2 times in dog_tags and 3 in cat_tags the join would result in 6 rows that share the same tag_id, so the counts would be wrong. Remember that a join is a Cartesian product of the rows of each joined table with a certain criteria. So, by grouping first by tag_id for each source table, we ensure that the tag_id appears only once in each table or derived table. And when we join the tables each tag_id will produce a single row.

夜灵血窟げ 2024-12-15 17:48:16

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

  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

顺便说一句,检查 unionunion all 之间的区别: mysql.com/doc/refman/5.0/en/union.html" rel="nofollow">http://dev.mysql.com/doc/refman/5.0/en/union.html。

I think your query is really complicated and you could try something like this:

  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 check the difference between union and union all: http://dev.mysql.com/doc/refman/5.0/en/union.html.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文