我认为最简单的方法是将团队连接在一起,然后加入结果。Postgres 提供了string_agg()
聚合字符串的功能:
select p1.playerId, p1.playerName, p2.playerId, p2.playerName
from (select p.playerId, string_agg(cast(p.TeamId as varchar(255)), ',' order by TeamId) as teams,
pp.PlayerName
from plays p join
players pp
on p.playerId = pp.playerId
group by p.playerId
) p1 join
(select p.playerId, string_agg(cast(p.TeamId as varchar(255)), ',' order by TeamId) as teams,
pp.PlayerName
from plays p join
players pp
on p.playerId = pp.playerId
group by p.playerId
) p2
on p1.playerid < p2.playerid and p1.teams = p2.teams;
编辑:
您可以在没有string_agg
. 这个想法是从所有可能的玩家组合的列表开始。
然后,使用 . 加入第一个玩家的团队left outer join
。full outer join
并通过使用和匹配团队和车手名称加入第二个团队。您需要驱动程序表的原因是确保 id/name 在完全外连接中不会丢失:
select driver.playerid1, driver.playerid2
from (select p1.playerId as playerId1, p1.playerName as playerName1,
p2.playerId as playerId2, p1.playerName as playerName2
from players p1 cross join
players p2
where p1.playerId < p2.playerId
) driver left outer join
plays p1
on p1.playerId = driver.playerId full outer join
plays p2
on p2.playerId = driver.playerId and
p2.teamid = p1.teamid
group by driver.playerid1, driver.playerid2
having count(p1.playerid) = count(*) and
count(p2.playerid) = count(*);
这加入了团队 id 上的两个玩家(订购,因此一对只被考虑一次)。然后,当两个玩家的所有行都具有非 NULL 团队值时,它会说存在匹配。having
使用等价子句可能更清楚:
having sum(case when p1.playerid is null then 1 else 0 end) = 0 and
sum(case when p2.playerid is null then 1 else 0 end) = 0;
NULL
当两个玩家的团队不匹配时,完全外部连接将产生值。因此,没有NULL
值意味着所有团队都匹配。