2012-04-17 1 views
2

Фон: Я работаю над проектом homebrew для управления коллекцией собственных изображений и пытаюсь реализовать поиск по тегам, чтобы я мог легко просеять их.Проблема с запросом на поиск/исключение тега «тег»

Прямо сейчас, я работаю с API-интерфейсом RedBean для применения тегов к записи базы данных каждого изображения, однако я зациклен на конкретной детали моей реализации; В настоящее время, чтобы поиск тегов, где несколько тегов уточнят поиск (при поиске «ABC XYZ», помеченное изображение должно иметь метки «ABC» и «XYZ»),

мне приходится обращаться с некоторыми обработки на серверном языке, а не SQL, а затем запустить (необязательный) второй запрос, чтобы убедиться, что у любых возвращенных изображений нет тега, который явно исключен из результатов. (при поиске «ABC -XYZ», помеченное изображение должно иметь метку «ABC» и не «XYZ»).

Проблема заключается в том, что мой текущий метод требует, чтобы я выполнял все результаты с помощью кода на стороне сервера и делал попытки ошибочного смещения нумерации страниц/результатов.

Моя цель состоит в том, чтобы просто захватить строки таблицы post, содержащие запрошенные теги (и не содержать исключенных тегов) с одним запросом, и все еще иметь возможность использовать аргументы LIMIT/OFFSET для моего запроса для получения обоснованного разбиения на страницы Результаты.

Таблица схема выглядит следующим образом:

Table "post" 
Columns: 
    id (PRIMARY KEY for post table) 
    (image metadata, not relevant to tag search) 

Table "tag" 
Columns: 
    id (PRIMARY KEY for tag table) 
    title (string of varying length - assume varchar(255)) 

Table "post_tag" 
Columns: 
    id (PRIMARY KEY for post_tag table) 
    post_id (associated with column "post.id") 
    tag_id (associated with column "tag.id") 

Если возможно, я хотел бы также иметь возможность WHERE условие, характерное для post столбцов таблицы, а также.

Что я должен использовать для структуры запроса? Я играл с левыми объединениями, но не смог получить точную структуру, необходимую мне для решения этой проблемы.

ответ

2

Вот основная идея:

LEFT OUTER JOIN есть множество сообщений, которые соответствуют тегам, которые вы хотите исключить. Заключительное предложение WHERE в запросе гарантирует, что ни один из этих сообщений не соответствует записям в первой таблице post.

INNER JOIN - это набор сообщений, соответствующих всем тегам. Обратите внимание, что номер два должен соответствовать числу уникальных имен тегов, которые вы указываете в предложении IN.

select p.* 
from post p 
left outer join (
    select pt.post_id  
    from post_tag pt 
    inner join tag t on pt.tag_id = t.id 
    where t.title in ('UVW', 'XYZ') 
) notag on p.id = notag.post_id 
inner join (
    select pt.post_id  
    from post_tag pt 
    inner join tag t on pt.tag_id = t.id 
    where t.title in ('ABC', 'DEF') 
    group by pt.post_id 
    having count(distinct t.title) = 2 
) yestag on p.id = yestag.post_id 
where notag.post_id is null 
--add additional WHERE filters here as needed 
+0

Не работает на SQLite, строки не возвращаются. Я быстро перевежу свою тестовую базу данных в MySQL и посмотрю, как это происходит. – damianb

+0

В MySQL нет ни одной кости. Имелось два сообщения в тестовом db, один помеченный '(« abc »,« def »,« ghi »)', другой отмеченный '(« abc »,« def »,« xyz »)'. Пробовал ваш запрос с помощью exclude/left-outer-join '(" xyz ")' и поиска/внутреннего объединения '(" abc "," def ")' без каких-либо результатов. Я немного потрудился со структурой и посмотрю, смогу ли я найти, где она злится. – damianb

+0

просто выполнил запрос с помощью «объяснения», я получаю это для первого фрагмента: «Невозможно, ГДЕ заметило после чтения таблиц const». – damianb