我有以下查询使用参考表 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
答案 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中直接替换列表。前一种方法不使用索引进行过滤。后者将(如果有合适的可用)。