Дополнительные исследования показали, что я уже ожидал: можно использовать решение, использующее оператор SQL IN, и оно фактически работает для удобной передачи этих запросов на сервер, но, возможно, не столь эффективно для большого количества тегов.
К счастью, пользователи не будут выполнять очень сложные запросы на регулярной основе и будут тратить немного времени на сложные запросы, поэтому я могу пренебречь этим в моем случае.
Чтобы связать источники для этих утверждений:
Чтобы в общих чертах набросать окончательное решение, вот код для этого:
Используя оператор IN в подзапросе, я могу отфильтровать все документы, к которым применен определенный атрибут. Комбинируя эти операторы IN с помощью AND / OR, я могу построить желаемое выражение.
SELECT i.Document
FROM Item i INNER JOIN Attribute a on i.Attribute = a.ID
WHERE
i.Document IN (
SELECT ii.Document
FROM Item ii INNER JOIN Attribute ai on ii.Attribute = ai.ID
WHERE ai.Name = "Smoker"
)
AND
i.Document IN (
SELECT ii.Document
FROM Item ii INNER JOIN Attribute ai on ii.Attribute = ai.ID
WHERE ai.Name = "Region-USA"
)
OR
i.Document IN (
SELECT ii.Document
FROM Item ii INNER JOIN Attribute ai on ii.Attribute = ai.ID
WHERE ai.Name = "Non-Smoker"
)
AND
i.Document IN (
SELECT ii.Document
FROM Item ii INNER JOIN Attribute ai on ii.Attribute = ai.ID
WHERE ai.Name = "Region-Europe"
)
AND
i.Document IN (
SELECT ii.Document
FROM Item ii INNER JOIN Attribute ai on ii.Attribute = ai.ID
WHERE ai.Name = "Hair-Blond"
)
Улучшение производительности
Чтобы ограничить количество JOIN, необходимых в подзапросах, можно сначала выбрать идентификаторы необходимых атрибутов.
SELECT ID, Name FROM Attribute WHERE Name in ('Smoker', 'Non-Smoker', ...)
Используя эти идентификаторы, подзапрос будет выглядеть намного проще, поскольку мы сможем пропустить JOIN:
SELECT i.Document
FROM Item i INNER JOIN Attribute a on i.Attribute = a.ID
WHERE
i.Document IN (SELECT ii.Document FROM Item ii WHERE ii.Attribute = 1) -- Smoker
AND
i.Document IN (SELECT ii.Document FROM Item ii WHERE ii.Attribute = 4) -- Region-USA
OR
...
Обновление
Измеренное время для обоих заходов
Я выполнил запрос, аналогичный указанному выше: (1 И 2) ИЛИ (3 И 4 И 4) на SQL Server с разумным размером набора Документов (130), Элементов (4122) и Атрибутов ( ~ 400).
Следующие времена могут быть измерены на моей машине:
- 1-й подход, с JOIN в подзапросе IN: ~ 12 секунд
- 2-й подход, сначала поиск атрибута по идентификатору: ~ 3,5 с