sql - 按多个标签选择(白名单和黑名单)

标签 sql sqlite

我有以下结构:

CREATE TABLE stories
(
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  dir TEXT,
  alias TEXT,
  title TEXT
);

CREATE TABLE tags
(
  story_id INTEGER,
  name TEXT
);


现在,我想选择所有(至少)具有N个标签且没有其他N个标签的故事。

示例:所有带有“幻想”和“自然”但没有“龙”的故事

这是我尝试过的查询(目前仅是“白名单”部分,但是它非常慢-所以我确定我做错了。

SELECT s.*
FROM stories s
WHERE 
   (SELECT COUNT(*)
       FROM tags t
       WHERE 
           t.story_id = s.id
           AND t.name IN ('fantasy', 'nature')
   ) = 2


如果我在末尾添加“ LIMIT 10”,它会起作用(但速度很慢)。

不过,不知道如何将黑名单条件包括到查询中。

有想法吗?

我有大约20.000个故事和75,000个标签条目。

最佳答案

这可以通过子查询轻松完成:

SELECT ...
FROM stories
WHERE id     IN (SELECT story_id FROM tags WHERE name = 'fantasy')
  AND id     IN (SELECT story_id FROM tags WHERE name = 'nature' )
  AND id NOT IN (SELECT story_id FROM tags WHERE name = 'dragons');


或者,使用compound query组合标签过滤器:

SELECT ...
FROM stories
WHERE id IN (SELECT story_id FROM tags WHERE name = 'fantasy'
             INTERSECT
             SELECT story_id FROM tags WHERE name = 'nature'
             EXCEPT
             SELECT story_id FROM tags WHERE name = 'dragons');


哪一个速度更快取决于您要检查的标签数量以及过滤器的选择性。您将不得不尝试。

如果tags.name列上有索引,则这两个查询都是有效的。

关于sql - 按多个标签选择(白名单和黑名单),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32574763/

相关文章:

SQL插入错误-"Subquery returned more than 1 value"

mysql - SQL 调用临时表中的列

sql - 无效的列名 '-'

mysql - 在复合 MySQL 语句中使用 max 和 limit

安卓。启动时升级数据库

Qt 和 SQLite 无法处理 'NULL' 值还是我做错了什么?

sqlite - 如何在 sqlite3 中创建具有默认值的日期时间列?

iphone - 如何使用sql查询获取特定项目项目的总工作时间(可能重复的外键)

android:在服务上尝试sqlite数据库时强制关闭

java - 获取表列的总数