Как эффективно запросить все строки в базе данных, соответствующие фильтру на основе объединенной таблицы? - PullRequest
1 голос
/ 18 апреля 2020

Извинения, если название вопроса неясно; Я не уверен, как сформулировать это без более подробной информации. У меня есть таблица foos как:

id (bigint) | details (json)
1           | {someKey: 'someValue' ...}
2           | {someKey: 'otherValue' ...}
...

У меня также есть таблица foo_labels как:

foo_id (bigint) | label_id (bigint)
1               | 10
2               | 13
...

Я заинтересован в том, чтобы получить все foo, соответствующие определенной метке фильтр. Например, если я хочу получить все фу с меткой 5 ИЛИ 6, я могу сделать:

select f.* from foos f 
join foo_labels fl on f.id = fl.foo_id
where fl.label_id in (5, 6)
group by f.id

Аналогично, я могу получить все фу с метками 5 И 6 что-то вроде:

select f.* from foos f
join foo_labels fl on f.id = fl.foo_id 
where fl.label_id in (5, 6)
group by f.id
having count(fl.label_id) = 2;

Но я застреваю с более сложными запросами. Например, как мне сделать запрос, чтобы получить все foos, которые имеют (метка 1 ИЛИ метка 2) И (метка 3 ИЛИ метка 4). Если говорить более абстрактно, я бы хотел выполнить запрос, чтобы получить все метки, содержащие метки, соответствующие группе предложений OR, и объединенные вместе, например:

(l_ {11} OR l_ {12 } ИЛИ ...) И (l_ {21} ИЛИ l_ {22} ИЛИ ...) И ...

Я пытался поиграть с этим, но не могу найти решение это включает только одну join таблицы foo_labels; Прямо сейчас единственный способ заставить его работать - это выполнить одно join за предложение ИЛИ. Есть ли способ сделать запрос, подобный этому, только присоединяясь к таблице foo_labels один раз? Я использую MySql, но если вы знаете, как это сделать в аналогичной версии SQL, это также может быть полезно?

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

(метка 1 ИЛИ метка 2) И (метка 3 ИЛИ метка 4)

В общем случае вы можете сделать это в предложении having без where. От join до foo ничего не добавляет полезного к запросу. Вот идея:

select fl.foo_id
from foo_labels fl 
group by fl.foo_id
having sum( label_id in (1, 2) ) > 0 and
       sum( label_id in (3, 4) ) > 0 ;

Это легко расширяемо для более сложных комбинаций.

1 голос
/ 18 апреля 2020

как мне сделать запрос, чтобы получить все foos, которые имеют (метка 1 ИЛИ метка 2) И (метка 3 ИЛИ метка 4)?

Вы можете иметь условные выражения в предложение having, например:

select f.* 
from foos f
join foo_labels fl on f.id = fl.foo_id 
where fl.label_id in (1, 2, 3, 4)
group by f.id
having 
    max(fl.label_id in (1, 2)) = 1
    and max(fl.label_id in (3, 4)) = 1
;

Предложение where не является строго необходимым, но оно делает запрос более эффективным, ограничивая количество строк перед агрегированием.

...