使用包含/排除池过滤查询

时间:2018-08-24 00:17:13

标签: sql sqlite

我有一个非常简单的标记系统,用于我的视频收藏,我正在使用它使用SQLite。我正在努力实现让我感到困惑的一项功能。我希望能够使用“包含/排除”池来检索视频。 IE:

  • 获取所有标记为'nature''grass''sky'
  • 的视频
  • 排除所有标记为'恐怖''gore'等的视频。

我的结构如下:

image of basic table structure

目前,我可以使用以下查询来提取带有标签的所有视频:

SELECT Media.filename FROM Tags 
INNER JOIN Media_Tags ON Tags.id = Media_Tags.tag_id 
INNER JOIN Media ON Media_Tags.media_id = Media.id 
WHERE Tags.name = 'people'

我试图做的是表演:

SELECT Media.filename FROM Tags 
INNER JOIN Media_Tags ON Tags.id = Media_Tags.tag_id 
INNER JOIN Media ON Media_Tags.media_id = Media.id 
WHERE Tags.name = 'people' 
AND Tags.name = 'seinfeld' 
AND Tags.name != 'elaine'
AND Tags.name != 'george'

当我看到我正在检索标签的所有视频而不是视频的所有标签时,问题变得很明显,因此,该操作始终返回零记录。在这一点上,我不确定是否要重写此查询。

有人可以为我提供一些有关如何实现这一目标的指导吗?

1 个答案:

答案 0 :(得分:2)

您可以通过聚合和having来做到这一点:

SELECT m.filename
FROM Tags t INNER JOIN
     Media_Tags mt
     ON t.id = mt.tag_id INNER JOIN
     Media m
     ON mt.media_id = m.id 
GROUP BY m.filename
HAVING SUM(CASE WHEN t.name = 'people' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN t.name = 'seinfeld' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN t.name = 'elaine' THEN 1 ELSE 0 END) = 0 AND
       SUM(CASE WHEN t.name = 'george' THEN 1 ELSE 0 END) = 0 ;

HAVING子句中的每个条件都会为每个filename上的每个标签测试一个条件。 > 0表示该标签存在; = 0说该标签不存在。

您的原始问题的回答方式也相同:

HAVING SUM(CASE WHEN t.name = 'nature' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN t.name = 'grass' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN t.name = 'sky' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN t.name = 'horror' THEN 1 ELSE 0 END) = 0 AND
       SUM(CASE WHEN t.name = 'gore' THEN 1 ELSE 0 END) = 0 ;