首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >涉及多个表的复杂SQL查询

涉及多个表的复杂SQL查询
EN

Stack Overflow用户
提问于 2013-07-31 10:53:06
回答 2查看 728关注 0票数 0

在这个查询中,我必须列出一对具有playerID和playerName的球员,他们为3支球队踢球,一个球员为3支球队踢球,另一对球员必须为3支球队踢球。不能少,不能多。如果两名球员目前没有为任何球队效力,他们也应该被包括在内。查询应该返回(playerID1,playername1,playerID2,playerName2),没有重复,比如如果玩家1的信息在玩家2之前,那么玩家2的信息不应该在玩家1之前。

例如,如果球员A效力于洋基队和红袜队,而球员B效力于洋基队、红袜队和道奇队,我就不应该得到他们。他们都必须为洋基和红袜队效力,而不是为其他人效力。现在,如果球员为任何同一支球队踢球,这个查询就会找到答案。

代码语言:javascript
复制
 player(playerID: integer, playerName: string)
 team(teamID: integer, teamName: string, sport: string)
 plays(playerID: integer, teamID: integer)

现在我得到的查询是

代码语言:javascript
复制
SELECT p1.playerID, p1.playerName, p2.playerID, p2.playerName
FROM player p1, player p2, plays
WHERE p1.teamID = p2.teamID AND teamID in.....

在这之后,我被困在了如何处理它上。任何关于如何处理这个问题的提示。耽误您时间,实在对不起。

EN

回答 2

Stack Overflow用户

发布于 2013-07-31 11:08:26

我认为最简单的方法是将团队连接在一起,然后根据结果加入。Postgres提供了聚合字符串的函数string_agg()

代码语言:javascript
复制
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/名称不会在完整的外连接中丢失:

代码语言:javascript
复制
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中的两名球员(通过排序,因此一对球员只被考虑一次)。然后,当两个玩家的所有行都有非空的Team值时,它就会说有一个匹配。使用等效的having子句可能会更清楚:

代码语言:javascript
复制
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值意味着所有团队都匹配。

票数 2
EN

Stack Overflow用户

发布于 2013-08-01 21:19:29

这是对您的previous questionmy answer的改编。

  1. 使用三角形连接获取所有唯一的玩家组合:

从player p1中选择p1.playerID,p1.playerName,p2.playerID,p2.playerName内加入player p2 ON p1.playerID < p2.playerID

  • Subtract第二个玩家的团队集合,检查结果中是否没有行:

不存在( SELECT teamID FROM plays WHERE playerID = p1.playerID除外SELECT teamID FROM plays WHERE playerID = p2.playerID )

  • 交换集合,减去并再次检查:

NOT EXISTS ( SELECT teamID FROM plays WHERE playerID = p2.playerID除外SELECT teamID FROM plays WHERE playerID = p1.playerID )

  • 最后,将这两个条件应用于步骤1中三角形连接的结果。

选择p1.playerID、p1.playerName、p2.playerID、p2.playerName FROM player p1内部加入player p2 ON p1.playerID < p2.playerID WHERE不存在( SELECT teamID FROM plays WHERE playerID = p1.playerID除外SELECT teamID FROM plays WHERE playerID = p2.playerID除外)和不存在( SELECT teamID FROM p1.playerID= p2.playerID除外SELECT teamID FROM FROM播放playerID = p1.playerID );

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17960808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档