我如何有效地查询数据库中与基于联接 table 的筛选器相匹配的所有行?

How can I efficiently query for all rows in a database matching a filter based on a joined table?

如果问题标题不清楚,我们深表歉意;如果没有更多细节,我不确定如何表达这一点。 我有一个 table foos 像:

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

我也有一个tablefoo_labels喜欢:

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

我有兴趣检索所有与特定标签过滤器匹配的 foo。例如,如果我想获取所有标签为 5 或 6 的 foo,我可以这样做:

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 的 foos:

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;

但我遇到了更复杂的查询。例如,我将如何进行查询以获取所有具有(标签 1 或标签 2)和(标签 3 或标签 4)的 foos。更抽象地说,我想执行一个查询来获取所有具有与一组 OR 子句匹配的标签的 foo,并将它们组合在一起,例如:

(l_{11} OR l_{12} OR ...) AND (l_{21} OR l_{22} OR ...) AND ...

我试过使用它,但找不到只涉及 foo_labels table 中的一个 join 的解决方案;现在我能让它工作的唯一方法是每个 OR 子句执行一个 join 。有没有办法在只加入 foo_labels table 一次的情况下进行这样的查询?我正在使用 MySql,但如果您知道如何在 SQL 的类似版本中执行此操作,那也可能有帮助吗?

how would I do a query to get all the foos that have (label 1 OR label 2) AND (label 3 OR label 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 子句不是绝对必要的,但它通过限制聚合前的行数来提高查询效率。

(label 1 OR label 2) AND (label 3 OR label 4)

一般来说,您可以在没有 wherehaving 子句中执行此操作。 joinfoo 对查询没有任何帮助。这是想法:

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 ;

这很容易扩展到更复杂的组合。