许多类型的系统使用标签来组织内容,包括博客和StackOverflow。假设我正在制作一个电影网站,并希望用户能够标记电影,以及使用标签组合搜索电影。
下面是一个示例数据库结构: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
假设有一部电影叫《变形金刚9 -爆炸》,它的标签是"动作"、"PG-13"answers"恐怖电影"。我希望用户能够通过搜索"动作,PG-13,恐怖电影"来找到这部电影。
我将在PHP中扩展标签字符串以获得一个标签数组:
action
PG-13
terrible movie
那么我的问题是,我如何使用标签名称来查找具有这些标签的电影?电影也可以有其他标签,但只有当它们包含搜索中的所有标签时才应该返回。
我能想到的唯一解决方案是将标签名称反规范化并将其存储在movie_tags
以及movie_tag_options
中(即向movie_tags
添加重复的name
列),然后在PHP中构建查询,为每个标签生成JOIN
语句。像这样:
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"
JOIN
行将通过PHP生成并插入查询。
这种方法的缺点是将标记名称存储在两个表中,而不是一个表中。
有更好的方法吗?
或者使用
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;