sql - 获取多对多关系的有效方法

标签 sql postgresql join many-to-many

我有以下表格:

team:     identifier, name
fan:      identifier, name
team_fan: team_identifier, fan_identifier

换句话说,球队和球迷之间是多对多的关系。

我想获取满足特定条件的所有团队;对于每个选定的团队,我想获取其所有粉丝。因此,在我的应用程序中,我希望具有以下数据结构:

Team A
     Fan F1
     Fan F2
Team B
     Fan F1
     Fan F3
Team C
     Fan F2
     Fan F3
     Fan F4

我已经想出了以下解决方案:

[0] 默认,典型方法

默认的典型方法是内部连接:

select     team.name, fan.name
from       team
inner join team_fan
on         team.identifier = team_fan.team_identifier
inner join fan
on         team_fan.fan_identifier = fan.identifier
where      ... (team conditions)

这提供了构建上述数据结构所需的所有信息。

有很多球队,球迷可以属于多个球队。上面的查询可能不是一个好主意,因为团队和粉丝在结果中是重复的。所有这些副本都需要通过网络传输。

在下面的备选方案中,我在应用程序中执行 JOIN。下面的替代方案可能会更慢,但我还不知道。我想从中比较和学习。

[1] 非常幼稚的做法

首先,我们选择所有团队:

select name from team where ...

然后,对于标识符为 X 的每个团队,我们选择其粉丝:

select name
from   fan
where  exists(select 1 from team_fan where team_identifier = X)

这是一个糟糕的解决方案,因为所需查询的数量是1 + 团队数量。此外,多次提取属于多个团队的粉丝。我们可以做得更好。

[2] 自上而下的方法

首先,我们选择所有团队。在这样做的同时,我们还将属于该团队的所有粉丝收集到一个数组中:

select  name, array(select identifier
                from   fan
                where  exists(select 1 from team_fan where fan.identifier = team_fan.fan_identifier and team.identifier = team_fan.team_identifier)) as fans
from  team
where ...

然后,在我们的应用程序中,我们构建了所有粉丝标识符的联合。给定这组粉丝标识符,我们可以选择所有粉丝:

select name from fan where identifier in(...)

现在,我有足够的信息在我的应用程序中复制 JOIN 并构建数据结构,如上所示。

这似乎是一个更好的解决方案。查询次数始终为 2。此外,每个团队和每个粉丝只获取一次。

[3] 自下而上的方法

我将之前的解决方案称为自上而下,因为我们正在向父级(团队)添加一组子级(粉丝)。在这种方法中,我们做相反的事情:我们将 parent (团队)数组添加到 child (粉丝)。

所以,首先,让我们选择所有团队:

select name from team where ...

接下来,在我们的应用程序中,我们构造所有团队标识符的并集。鉴于这组球队标识符,我们可以选择所有球迷:

select name, array(select team_fan.team_identifier from team_fan where fan_identifier = fan.identifier and team_identifier in(...))
from   fan
where  exists(select 1 from team_fan where fan_identifier = fan.identifier and team_identifier in(...));

现在,我有足够的信息在我的应用程序中复制 JOIN 并构建数据结构,如上所示。

这似乎也是一个有效的解决方案。同样在这种情况下,查询的数量始终为 2。此外,每个团队和每个粉丝只被获取一次。

我的问题

所以,回到我的问题:我想获取满足特定条件的所有团队;对于每个选定的团队,我想获取其所有粉丝。

目前,我不确定方法 2 是否优于方法 3(反之亦然),甚至不确定是否有更好的方法。欢迎任何见解。

最佳答案

做一个简单的连接

Select
    t.identitfier team_identifier
    ,t.name team_name
    ,f.identitfier fan_identifier
    ,f.name fan_name
From team t 
inner join team_fan tf 
on t.identifier=tf.team_identifier
/* and --(team condition can be put here) */
inner join fan f on tf.fan_identifier=f.identifier
/*where ... --(or team condition can be put here)*/

关于sql - 获取多对多关系的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45735285/

相关文章:

sql - 在任何一周内为员工获取 2 个或更多市场的发票

postgresql - 如何运行postgresql函数(运行时看到错误)

sql - 困难的 SQL 子查询来计算一些东西

mysql - 选择不符合此联接条件的行

sql - 内连接和并集均使用 order by

sql - Postgresql 数组包含条目的数量?

sql - 如何快速删除SQL数据库中的大量记录?

mysql - 在 SQL 中获取特定事件之前的所有记录

windows - 用于将 psql 查询输出存储到变量中的批处理文件

java - Spark-Java : Display join RDD