Mysql连接查询匹配所有标签的多个“标签”(多对多关系)?

Posted

技术标签:

【中文标题】Mysql连接查询匹配所有标签的多个“标签”(多对多关系)?【英文标题】:Mysql join query for multiple "tags" (many-to-many relationship) that matches ALL tags? 【发布时间】:2011-03-17 02:33:34 【问题描述】:

我正在尝试查询与所有给定标签集匹配的对象。

基本上,我希望用户能够添加越来越多的标签来过滤或“缩小”他们的搜索结果,就像 newegg.com 所做的那样。

我的表结构是一个对象表、一个标签表和一个 MANY:MANY 关系表 ObjectsTags。所以我有一个这样的 JOIN 查询:

SELECT * FROM Objects
LEFT OUTER JOIN ObjectsTags ON (Objects.id=ObjectsTags.object_id)
LEFT OUTER JOIN Tags ON (Tags.id=ObjectsTags.tag_id)

我尝试使用 IN 子句/条件,如下所示:

SELECT * FROM Objects
LEFT OUTER JOIN ObjectsTags ON (Objects.id=ObjectsTags.object_id)
LEFT OUTER JOIN Tags ON (Tags.id=ObjectsTags.tag_id)
WHERE Tags.name IN ('tag1','tag2')
GROUP BY Objects.id

但我了解到,这模拟了一系列 OR,因此添加到查询中的标签越多,得到的结果就越多,而不是像我希望的那样缩小结果集。

我还尝试了多个 LIKE WHERE 条件,并一起使用:

SELECT * FROM Objects
LEFT OUTER JOIN ObjectsTags ON (Objects.id=ObjectsTags.object_id)
LEFT OUTER JOIN Tags ON (Tags.id=ObjectsTags.tag_id)
WHERE Tags.name LIKE 'tag1' 
AND Tags.name LIKE 'tag2'
GROUP BY Objects.id

但这不会返回任何结果,因为当结果组合在一起时,OUTER JOINed Tags.name 列只包含“tag1”,而不包含“tag2”。 'tag2' 匹配的结果行​​被 GROUPing “隐藏”。

如何匹配所有标签以获得我所追求的“缩小”或“向下钻取”效果?谢谢。

【问题讨论】:

【参考方案1】:

用途:

  SELECT * 
    FROM OBJECTS o
    JOIN OBJECTSTAGS ot ON ot.object_id = o.id
    JOIN TAGS t ON t.id = ot.tag_id
   WHERE t.name IN ('tag1','tag2')
GROUP BY o.id
  HAVING COUNT(DISTINCT t.name) = 2

您缺少 HAVING 子句。

如果您只想要两个标签都存在的行,则无需 LEFT JOIN。

【讨论】:

如果您在 OBJECTTAGS 中的这对列上没有主键或唯一约束/索引以确保没有重复项(这些将是误报),则 DISTINCT 是必要的。跨度> 效果很好!谢谢!从未想过以这种方式使用 HAVING 来计算行数。供其他人参考:我正在用 php 构建查询,以便 HAVING 子句与我正在搜索的标签数量相匹配,所以如果它是 ('tag1', 'tag2', 'tag3') 我正在寻找 HAVING COUNT(DISTINCT t.name) = 3,以确保他的结果具有所有标签。 很棒的答案。谢谢! 这个答案救了我的命!非常感谢!

以上是关于Mysql连接查询匹配所有标签的多个“标签”(多对多关系)?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL选择连接多对多表加上IN和NOT IN

优化查询以匹配和排除多个多对多条目

JPQL在多对多关系上左外连接

无论如何,为了提高 SQL 查询的性能,以按标签匹配计数查找具有顺序的行

按标签、多对多关系查找所有文章

在 MySQL 中使用多个标签搜索标签表或“全选”