我有以下表格:
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 ║
╚═══════╩══════╩═══════════╩════════════════╝
答案 0 :(得分: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
答案 1 :(得分: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
答案 2 :(得分: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
)
;
BTW:从ta.idTag=t.id
开始,可能会省略与tha标签表的连接(给定正确的FK约束)。