I have a HABTM relationship between 'articles' and 'tags'
Problem: I'm only looking for articles with BOTH the tag 'sports' and 'outdoors' but not articles with only one of these tags.
I tried this:
SELECT DISTINCT article.id, article.name FROM articles
inner JOIN tags ON (tags.name IN ('outdoors', 'sports')
inner JOIN articles_tags ON articles_tags.article_id = article.id AND articles_tags.tag_id = tags.id
...but it gets me articles that are in only sports, only outdoors AND both sports + outdoors
Question what is the right query to use? (I'm using MySQL)
There are two common solutions.
The first solution uses
GROUP BY
to count the tags per article that match 'outdoors' or 'sports' and then returns only the groups that have both tags.This solution appears more readable to some people, and adding values is more straightforward. But
GROUP BY
queries in MySQL tend to incur a temporary table which harms performance.The other solution uses a
JOIN
per distinct tag. By using inner joins, the query naturally restricts to articles that match all the tags you specify.Assuming
tags.name
andarticles_tags.(article_id,tag_id)
both haveUNIQUE
constraints, you shouldn't need aDISTINCT
query modifier.This type of query tends to optimize better on MySQL than the
GROUP BY
solution, assuming you have defined appropriate indexes.Re your followup question in the comment, I would do something like this:
This still only finds articles that have both tags 'outdoors' and 'sports', but then it further joins these articles to all its tags.
This will return multiple rows per article (one for each tag) so we then use
GROUP BY
to reduce down to a single row per article again.GROUP_CONCAT()
returns a comma-separated list of the values in the respective group.