MySQL复合连接用于多个包含和排除

时间:2012-08-13 07:22:24

标签: mysql inner-join

我有一个客户要我制作标签系统。我有三个表:itemstagsitem_tag_assoc - 最后一个表只用于关联item_ids和tag_ids。这是我遇到的问题:

如果用户请求包含标签[1,2,3]和排除标签[4,5,6],则结果应该是[1,2]中包含 EVERY 标签的所有项目3 [5,5]中的(不仅仅是一个)和 NO 标签。如何编写查询来完成此任务?

我研究得足以找出标签包含的内连接:

SELECT i.item_id, i.item_title FROM items AS i INNER JOIN tag_item_assoc AS tia1 ON (tia1.item_id = i.item_id AND tia1.tag_id = 1)

...并且只需要链接到相同的内部联接模式,即可以包含任意数量的标记。它可能有点笨重,但用户在继续前不会选择超过4或5个标签,所以它会这样做。

我真的希望我能以同样的方式排除,并将所有内容都包装在一个查询中:

INNER JOIN tag_item_assoc AS tia2 ON (tia2.item_id = i.item_id AND tia2.tag_id!= 2)

但很快就会发现它不会起作用。我读了几篇文章,说LEFT OUTER JOIN可以让我在我加入时排除,但我无法弄明白,主要是因为流浪WHERE条款。我试过的LEFT OUTER JOININNER JOIN的任何排列都会产生错误或非常令人困惑的结果。

所有这一切 - 这里的任何人都知道如何实现这一目标吗?我为没有提供任何有用的代码示例而道歉。如果INNER JOIN是一个障碍,我可以从头开始 - 我只需要一种方法同时完成多个关联包含和排除。提前感谢您的帮助和专业知识!

3 个答案:

答案 0 :(得分:0)

您需要将记录实例数与标记数相匹配:

SELECT a.item_id -- , add other columns here
FROM   items a
          INNER JOIN item_tag_assoc b
             ON a.item_id = b.item_id
WHERE b.tag_id IN (1, 2, 3) AND
      b.tag_id NOT IN (4, 5, 6)
GROUP BY a.item_id
HAVING COUNT(a.item_id) = 3

答案 1 :(得分:0)

SELECT a.*
FROM items a
     INNER JOIN item_tag_assoc b
         ON a.item_id = b.item_id
     INNER JOIN tags c
         ON a.tag_id = c.tag_id
WHERE c.tag_id IN(1) AND
      c.tag_id IN(2) AND
      c.tag_id IN(3) AND
      c.tag_id NOT IN (4) AND
      c.tag_id NOT IN (5) AND
      c.tag_id NOT IN (6) ;

答案 2 :(得分:0)

找到答案。而不是像这样添加INNER JOIN

INNER JOIN tag_item_assoc AS tia2 ON (tia2.item_id = i.item_id AND tia2.tag_id!= 2)

我添加了一个带有单个内连接的子查询:

WHERE i.item_id NOT IN ( SELECT i.item_id FROM items AS s INNER JOIN tag_item_assoc AS tia1 ON (tia1.item_id = i.item_id AND tia1.tag_id IN (4, 5, 6)))

子查询创建一组所有item,其中包含[4,5,6]和WHERE i.iten_id NOT IN中的任何标记,可以消除与该集合匹配的任何记录。

感谢大家的努力!希望这会有所帮助。