Reputation: 28354
Many types of systems use tags to organize content, including blogs and StackOverflow. Let's say I'm making a movies website and want users to be able to tag movies, as well as search for movies using combinations of tags.
Here's a sample database structure:
movies:
id, name
movie_tag_options (used to provide users with list of available tag options):
id, name
movie_tags:
id, m_id, mto_id
Let's say there's a movie called "Transformers 9 - Explosions" and it has the tags "action", "PG-13", and "terrible movie". I want users to be able to find this movie by performing a search for "action,PG-13,terrible movie".
I will explode the string of tags in PHP to get an array of tags:
action
PG-13
terrible movie
So my question is, how do I use the tag names to find movies with these tags? The movies can have other tags as well, but should only be returned if they have all of the tags in the search.
The only solution I can think of is to denormalize the tag name and to store it in movie_tags
as well as movie_tag_options
(i.e. adding a duplicate name
column to movie_tags
), then constructing a query in PHP that generates JOIN
statements for each tag. Something like this:
SELECT id, name FROM movies
JOIN movie_tags mt0 ON mt0.name = "action"
JOIN movie_tags mt1 ON mt1.name = "PG-13"
JOIN movie_tags mt2 ON mt2.name = "terrible movie"
The JOIN
lines would be generated via PHP and inserted into the query.
The downside to this approach is storing the tag names in two tables instead of one.
Is there a better way?
Upvotes: 0
Views: 119
Reputation: 12772
or you can use
select a.name, count(c.id) c
from movies a
join movie_tags b on a.id = b.m_id
join movie_tag_options c on b.mto_id = c.id
where c.name in ('action', 'PG-13', 'terrible movie')
group by a.id
having c = 3;
Upvotes: 2