Я впервые неправильно прочитал вопрос и подумал, что он спрашивает
(1 AND 2 AND 5) OR (6 AND 7) OR (10)
вместо правильного
(1 OR 2 OR 5) AND (6 OR 7) AND (10)
Все ответы до сих пор были сосредоточены на том, чтобы ответить на конкретный пример, а не на более общий вопрос "и предположим, что в следующий раз я хочу другой набор критериев".
Актуальный вопрос
Я не могу сделать намного лучше, чем выбранный ответ на фактический вопрос ( Запрос 1 ):
SELECT r.id, r.name
FROM Records AS r
WHERE EXISTS(SELECT * FROM SearchTags AS s
WHERE r.id = s.recordid AND s.id IN (1, 2, 5))
AND EXISTS(SELECT * FROM SearchTags AS s
WHERE r.id = s.recordid AND s.id IN (6, 7))
AND EXISTS(SELECT * FROM SearchTags AS s
WHERE r.id = s.recordid AND s.id IN (10));
Это можно записать как объединение трех псевдонимов для таблицы SearchTags.
Альтернативный вопрос
Есть несколько способов ответить на альтернативу - я думаю, что это наиболее аккуратный и расширяемый вариант. Очевидно, что один элемент (10) прост ( Запрос 2 ):
SELECT r.id, r.name
FROM records AS r JOIN searchtags AS t ON r.id = t.recordid
WHERE t.id IN (10) -- or '= 10' but IN is consistent with what follows
Два элемента (6 или 7) можно выполнить с помощью ( Запрос 3 ):
SELECT r.id, r.name
FROM records AS r JOIN searchtags AS t ON r.id = t.recordid
WHERE t.id IN (6, 7)
GROUP BY r.id, r.name
HAVING COUNT(*) = 2
Три элемента (1, 2, 5) можно выполнить с помощью ( Запрос 4 ):
SELECT r.id, r.name
FROM records AS r JOIN searchtags AS t ON r.id = t.recordid
WHERE t.id IN (1, 2, 5)
GROUP BY r.id, r.name
HAVING COUNT(*) = 3
И вся коллекция может быть СОЮЗОМ из трех терминов.
Обобщение решений
Недостатком этого решения является то, что SQL должен создаваться вручную для каждого набора элементов.
Если вы хотите автоматизировать «генерацию SQL», вам нужны контрольные данные - наборы интересных поисковых тегов - в таблице:
CREATE TABLE InterestingTags(GroupID INTEGER, TagID INTEGER);
INSERT INTO InterestingTags(1, 1);
INSERT INTO InterestingTags(1, 2);
INSERT INTO InterestingTags(1, 5);
INSERT INTO InterestingTags(2, 6);
INSERT INTO InterestingTags(2, 7);
INSERT INTO InterestingTags(3, 10);
Для запроса, запрашивающего '(1 ИЛИ ИЛИ 5) И (...)' (конъюнктивная нормальная форма), вы можете написать ( Запрос 5 ):
SELECT r.id, r.name
FROM records AS r JOIN
searchtags AS s ON r.id = s.recordID JOIN
interestingtags AS t ON s.id = t.tagID
GROUP BY r.id, r.name
HAVING COUNT(DISTINCT t.GroupID) = (SELECT COUNT(DISTINCT GroupID)
FROM InterestingTags);
Это проверяет, что количество различных «интересных групп тегов» для данной записи равно общему количеству «интересных групп тегов».
Для запроса, запрашивающего '(1 И 2 И 5) ИЛИ (...)' (дизъюнктивная нормальная форма), вы можете написать объединение с InterestingTags и проверить, что запись имеет столько записей, сколько и группа тегов. ( Запрос 6 ):
SELECT i.id, i.name
FROM (SELECT q.id, q.name, c.GroupSize,
COUNT(DISTINCT t.GroupID) AS GroupCount
FROM records AS q JOIN
searchtags AS s ON q.id = s.recordID JOIN
interestingtags AS t ON s.id = t.tagID JOIN
(SELECT GroupID, COUNT(*) AS GroupSize
FROM InterestingTags
GROUP BY GroupID) AS c ON c.GroupID = t.GroupID
GROUP BY q.id, q.name, c.GroupSize
) AS i
WHERE i.GroupCount = i.GroupSize;
Данные испытаний
Я взял тестовые данные из ответа Даниэля Вассало и дополнил их некоторыми дополнительными значениями:
CREATE TABLE records (id int, name varchar(10));
CREATE TABLE searchtags (id int, recordid int);
INSERT INTO records VALUES (1, 'a');
INSERT INTO records VALUES (2, 'b');
INSERT INTO records VALUES (3, 'c');
INSERT INTO records VALUES (4, 'd');
INSERT INTO records VALUES (11, 'A11');
INSERT INTO records VALUES (21, 'B12');
INSERT INTO records VALUES (31, 'C13');
INSERT INTO records VALUES (41, 'D14');
INSERT INTO records VALUES (51, 'E15');
INSERT INTO records VALUES (61, 'F16');
INSERT INTO searchtags VALUES (1, 1);
INSERT INTO searchtags VALUES (2, 1);
INSERT INTO searchtags VALUES (6, 1);
INSERT INTO searchtags VALUES (10, 1);
INSERT INTO searchtags VALUES (1, 2);
INSERT INTO searchtags VALUES (2, 2);
INSERT INTO searchtags VALUES (3, 2);
INSERT INTO searchtags VALUES (1, 3);
INSERT INTO searchtags VALUES (10, 3);
INSERT INTO searchtags VALUES (5, 4);
INSERT INTO searchtags VALUES (7, 4);
INSERT INTO searchtags VALUES (10, 4);
INSERT INTO searchtags VALUES (1, 11);
INSERT INTO searchtags VALUES (2, 11);
INSERT INTO searchtags VALUES (5, 11);
INSERT INTO searchtags VALUES (6, 21);
INSERT INTO searchtags VALUES (7, 21);
INSERT INTO searchtags VALUES (10, 31);
INSERT INTO searchtags VALUES (1, 41);
INSERT INTO searchtags VALUES (6, 41);
INSERT INTO searchtags VALUES (10, 41);
INSERT INTO searchtags VALUES (2, 51);
INSERT INTO searchtags VALUES (5, 51);
INSERT INTO searchtags VALUES (10, 51);
INSERT INTO searchtags VALUES (7, 61);
INSERT INTO searchtags VALUES (2, 61);
INSERT INTO searchtags VALUES (1, 61);
CREATE TABLE InterestingTags(GroupID INTEGER, TagID INTEGER);
INSERT INTO InterestingTags VALUES(1, 1);
INSERT INTO InterestingTags VALUES(1, 2);
INSERT INTO InterestingTags VALUES(1, 5);
INSERT INTO InterestingTags VALUES(2, 6);
INSERT INTO InterestingTags VALUES(2, 7);
INSERT INTO InterestingTags VALUES(3, 10);
Результаты теста
Выводы, которые я получил, были:
Запрос 1
1 a
4 d
41 D14
Запрос 2
1 a
3 c
4 d
31 C13
41 D14
51 E15
Запрос 3
21 B12
Запрос 4
11 A11
Запрос 5
1 a
41 D14
4 d
Запрос 6
4 d
31 C13
3 c
1 a
41 D14
51 E15
Очевидно, что если бы я хотел вывод в определенном порядке, я бы добавил к запросам предложение ORDER BY.