2015-09-14 2 views
1

I имеют следующую структуру:Выбор по нескольким тегам (белый список и черный список)

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 записей тегов.

+0

Ответьте, если вы хотите очки, но я решил его другим способом, используя запрос LIKE в столбце со всеми конкатенированными тегами. – MightyPork

ответ

1

Это можно легко сделать с помощью подзапросов:

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.

Смежные вопросы