Mysql内部联接管理count()行为

时间:2013-07-27 13:25:39

标签: mysql count inner-join

我有以下查询使用参考表 tags_titles tags_blogs 来比较包含其中名为标记的标记的表格。标签本身保存在 t.label 列中。

我的问题是,有时 count()过多的total_matches 。通常可以在tags_titles和tags_blogs中找到标记。是否有任何方法可以使内连接相互排斥,或其他解决方案,以便与列t.label的实际匹配计数准确?

SELECT b.blog_id AS id, b.title AS title, b.body AS body, COUNT(t.label) AS total_matches, b.creation_time AS creation_time, '1' AS type
FROM tags AS t 
INNER JOIN tags_titles AS tt
ON tt.tag_id = t.tag_id
INNER JOIN tags_blogs AS tb
ON tb.tag_id = t.tag_id
INNER JOIN blogs AS b
ON tt.blog_id=b.blog_id OR tb.blog_id=b.blog_id
WHERE t.label IN ($in) AND b.title IS NOT NULL
GROUP BY id, title, body, creation_time, type

1 个答案:

答案 0 :(得分:4)

您的问题是标题的标签列表和博客的标签列表,您将获得每个博客的这些标签的笛卡尔积。

解决问题的简单方法是使用count(distinct)

SELECT b.blog_id AS id, b.title AS title, b.body AS body, COUNT(distinct t.label) AS total_matches,
       b.creation_time AS creation_time, '1' AS type
FROM tags AS t 
INNER JOIN tags_titles AS tt
ON tt.tag_id = t.tag_id
INNER JOIN tags_blogs AS tb
ON tb.tag_id = t.tag_id
INNER JOIN blogs AS b
ON tt.blog_id=b.blog_id OR tb.blog_id=b.blog_id
WHERE t.label IN ($in) AND b.title IS NOT NULL
GROUP BY id, title, body, creation_time, type;

在更复杂的场景中,有时需要在连接之前独立地沿着单独的维聚合。

您还有另一个问题t.label in ($in)。这不适用于。您可以使用:

find_in_set(t.label, $in) > 0;

或者在SQL中直接替换列表。前一种方法不使用索引进行过滤。后者将(如果有合适的可用)。