使用 SQL 过滤

Filtering with SQL

我正在尝试编写一个 SQL 查询来过滤数据集中的人员。

有一些"facets",比如"How old is the person?","How tall is the person?"。

每个方面都有一些 "buckets"。例如,"How old?" 方面可能有桶“0-20”、“21-40”、“40+”。

有一些 "memberships",这是一个连接 table 来声明一个人属于特定的桶。

我的模型是这样的:

  Facet
    |
   /|\
  Bucket
    |
   /|\
Membership
   \|/
    |
  Person

我遇到困难的部分是,为了能够进行过滤,我需要在各个方面进行交集。

例如,我希望能够为 "How old?" 选择“0-20”和“21-40”,为 "How tall?" 选择“0-140”。返回的人应该是:

(桶“0-20”中的人或桶“21-40”中的人)和桶“0-140”中的人

我不太确定该怎么做。我可以使用 "IN" 子句轻松完成 "OR",例如IN (1, 2, 3),但我不确定 "AND"。我看到 SQL 有一个 "INTERSECT" 关键字,但我不确定这是否是正确的方法。

非常感谢任何帮助。

谢谢

编辑:这是(简化的)架构:

方面:id

桶:id,facet_id

成员资格:person_id、bucket_id

人:id

所有字段都是整数。

编辑:这是我迄今为止最好的查询。

select group_concat(p.id) as "people for facet",
b.facet_id from people p
join memberships m on m.person_id = p.id
join buckets b on m.bucket_id = b.id
where b.id in (1, 3)
group by b.facet_id;

我现在需要将 "people for facet" 结果相交。

假设任何给定的桶只是单个方面的一部分,那么有一个非常优雅的解决方案。挑战在于以正确的方式看待问题。所以,如果您想要匹配您所有方面的用户,

select b.userid
from buckets b
where b.bucketid in ( . . . )
group by b.userid
having count(distinct b.facetid) = # of facets;

我们的想法是您有一个存储桶列表并表示您想要的方面。您希望确保每个 "facet" 至少有一个匹配的存储桶,这就是 having 子句的作用。

谢谢戈登。我终于明白了!您对问题的颠倒思考方式有所帮助。

这是我的解决方案:

select p.* from memberships m
join people p on m.person_id = p.id
join buckets b on m.bucket_id = b.id
where b.id in (1, 3)
group by m.person_id
having count(distinct b.facet_id) = (
  select count(distinct b.facet_id) from buckets b
  where b.id in (1, 3)
);

输入是桶列表 (1, 3)。

我使用子查询来计算这些桶的分面数。也许有更高效的方法,但我认为无论如何都会很快执行。

我将在大型数据集上对此进行测试,看看它的表现如何。

再次感谢。