查询以搜索包含所有请求标签的歌曲

Query to search for the songs to contain all the requested tags

我正在为使用标签的歌曲创建一个搜索引擎,但我在构建 SQL 查询以列出所有与标签匹配的歌曲时遇到了问题。

数据库如下所示: http://i.imgur.com/5zmfAz8.png

歌曲通过中间层有很多标签table(SongTags)。

让我们以人口为例:

标签: 电子、器乐、活力、忧郁、声乐、摇滚

歌曲: SongA(电子、忧郁、声乐) SongB(器乐、忧郁、摇滚) SongC(精力充沛,声乐)


搜索应该 return 包含请求的所有标签的歌曲。

搜索 1:

"Vocal" returns: 歌曲A, 歌曲B

搜索 2:

"Vocal", "Energetic" returns:宋C

搜索 3:

"Vocal", "Energetic", "Electro" returns: 无


我知道如何搜索 1 个标签,而不是多个标签。 例如 Search1,我知道这会起作用:

SELECT * FROM "songs"
INNER JOIN "song_tags" ON "song_tags"."song_id" = "songs"."id"
INNER JOIN "tags" ON "tags"."id" = "song_tags"."tag_id"
WHERE "tags"."name" = 'Vocal'

但是我不知道如何执行 Search2,因为我需要歌曲同时包含 "Vocal" 和 "Energetic"。

编辑:

我正在使用 PostgreSQL

SELECT songs.*, COUNT(songs.id) AS total FROM "songs"
INNER JOIN "song_tags" ON "song_tags"."song_id" = "songs"."id"
INNER JOIN "tags" ON "tags"."id" = "song_tags"."tag_id"
WHERE "tags"."name" IN ('Vocal', 'Energetic')
GROUP BY songs.id
HAVING total = 2

如果您想获得与所有 标签匹配的歌曲,我会使用子选择。它们会有点慢,但它会给你一个百搭的解决方案:

SELECT songs.* FROM songs
  WHERE songs.song_id IN
    (SELECT song_tags.song_id FROM song_tags st JOIN tags t ON st.tag_id = t.id AND t.name = 'VOCAL')
   AND songs.song_id IN (SELECT song_tags.song_id FROM song_tags st JOIN tags t ON st.tag_id = t.id AND t.name = 'ENERGETIC')

如果您的 SQL 服务器支持 INTERSECT 命令,您可以这样做:

SELECT songs.* FROM songs
  WHERE songs.song_id IN
    (SELECT song_tags.song_id FROM song_tags st JOIN tags t ON st.tag_id = t.id AND t.name = 'VOCAL' 
    INTERSECT
   SELECT song_tags.song_id FROM song_tags st JOIN tags t ON st.tag_id = t.id AND t.name = 'ENERGETIC')

我认为这是一种更酷的方式。

希望对您有所帮助。 :)