2

我有以下表格:

articles: id, title, content
tags: id, tag, tagCategory
tags2articles: id, idTag, idArticle
categories: id, title, someOtherFields

在一个页面中,我需要选择所有具有多个标签的文章。我正在使用这个:

SELECT
   SQL_CALC_FOUND_ROWS a.* 
FROM 
  articles AS a
  JOIN tags2articles AS ta  ON a.id=ta.idArticle
  JOIN tags AS t ON ta.idTag=t.id
WHERE 
  t.id IN (12,13,16) 
GROUP BY a.id
HAVING
  COUNT(DISTINCT t.id)=3

这将选择所有具有 ID 为 12,13 和 16 的标签的文章,并且工作正常。但是,所选文章也可能具有其他标签,这些标签可能仅特定于其中一个或多个。

棘手的部分来了:我想使用这些标签来制作一些过滤器,所以我需要另一个查询来选择上面文章所具有的所有不同标签。像这样的东西:

╔═══════╦══════╦═══════════╦════════════════╗
║ TagID ║ Tag  ║ Category  ║ SomeOtherField ║
╠═══════╬══════╬═══════════╬════════════════╣
║ id1   ║ tag1 ║ category1 ║ field1         ║
║ id2   ║ tag2 ║ category2 ║ field2         ║
║ id3   ║ tag3 ║ category1 ║ field1         ║
║ id4   ║ tag4 ║ category3 ║ field3         ║
╚═══════╩══════╩═══════════╩════════════════╝
4

3 回答 3

5

使用与您已有的类似查询作为要加入的派生表(但没有所有a.*列),您可以执行INNER JOIN反对tags2articles以获取这些文章 ID 具有的剩余标签。

这应该导致任何匹配文章持有的所有标签的不同列表。

SELECT 
  DISTINCT
  t.id,
  t.tag, 
  c.title AS Category
FROM
  tags2Articles t2a 
  INNER JOIN tags t ON t.id = t2a.idTag
  INNER JOIN categories c ON t.tagCategory = c.id
  /* Subquery join returns article ids having all 3 tags you filtered */
  /* Joining against tags2articles again will get the remaining tags for these articles */
  INNER JOIN (
    SELECT
     a.id 
    FROM 
     articles AS a
     JOIN tags2articles AS ta  ON a.id=ta.idArticle
     JOIN tags AS tsub ON ta.idTag=tsub.id
    WHERE 
      tsub.id IN (12,13,16) 
    GROUP BY a.id
    HAVING COUNT(DISTINCT tsub.id)=3 
  ) asub ON t2a.idArticle = asub.id
于 2012-12-29T14:24:24.243 回答
2

这是对迈克尔答案的重写,删除了无关的连接:

SELECT DISTINCT t.id, t.tag, c.title AS Category
FROM tags2Articles t2a INNER JOIN
     tags t
     ON t.id = t2a.idTag INNER JOIN
     categories c ON t.tagCategory = c.id inner join
     /* Subquery join returns article ids having all 3 tags you filtered */
     /* Joining against tags2articles again will get the remaining tags for these articles */
     (SELECT t2a.idArticle
      FROM tags2articles t2a
      WHERE t2a.idTag IN (12,13,16) 
      GROUP BY t2a.idArticle
      HAVING COUNT(DISTINCT t2a.idTag)=3 
    ) asub
    ON t2a.idArticle = asub.idArticle
于 2012-12-29T15:57:48.927 回答
0

这可能看起来很难看,但它可能会更快

SELECT a.*
FROM articles AS a
WHERE 1=1
AND EXISTS (
  SELECT *
  FROM tags2articles AS ta   
  JOIN tags AS t ON ta.idTag=t.id
  WHERE  a.id=ta.idArticle AND t.id = 12
  )
AND EXISTS (
  SELECT *
  FROM tags2articles AS ta  
  JOIN tags AS t ON ta.idTag=t.id
  WHERE  a.id=ta.idArticle AND t.id = 13
  )
AND EXISTS (
  SELECT *
  FROM tags2articles AS ta  
  JOIN tags AS t ON ta.idTag=t.id
  WHERE  a.id=ta.idArticle AND t.id = 16
  )
  ;

顺便说一句:由于ta.idTag=t.id.

于 2012-12-30T15:20:02.333 回答