0

在此查询中,我必须列出为完全相同的球队效力的一对球员及其 playerID 和 playerName。如果一名球员为 3 支球队效力,则另一个必须为完全相同的 3 支球队效力。不多,不多。如果两名球员目前没有为任何球队效力,他们也应该被包括在内。查询应返回 (playerID1, playername1, playerID2, playerName2) 且不重复,例如如果玩家 1 信息出现在玩家 2 之前,则不应有另一个元组包含玩家 2 信息在玩家 1 之前。

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

 player(playerID: integer, playerName: string)
 team(teamID: integer, teamName: string, sport: string)
 plays(playerID: integer, teamID: integer)

现在我的查询是

SELECT p1.playerID, p1.playerName, p2.playerID, p2.playerName
FROM player p1, player p2, plays
WHERE p1.teamID = p2.teamID AND teamID in.....

我被困在如何处理它之后。有关如何解决此问题的任何提示。谢谢你的时间。

4

2 回答 2

2

我认为最简单的方法是将团队连接在一起,然后加入结果。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 joinfull 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值意味着所有团队都匹配。

于 2013-07-31T03:08:26.383 回答
0

这是我对你之前一个问题的回答的改编。

  1. 使用三角连接获得所有独特的玩家组合:

    SELECT p1.playerID, p1.playerName, p2.playerID, p2.playerName
    FROM player p1
    INNER JOIN player p2 ON p1.playerID < p2.playerID
    
  2. 从第一个玩家的团队集合中减去第二个玩家的团队集,并检查结果中是否没有行:

    NOT EXISTS (
        SELECT teamID
        FROM plays
        WHERE playerID = p1.playerID
    
        EXCEPT
    
        SELECT teamID
        FROM plays
        WHERE playerID = p2.playerID
    )
    
  3. 交换集合,减去并再次检查:

    NOT EXISTS (
        SELECT teamID
        FROM plays
        WHERE playerID = p2.playerID
    
        EXCEPT
    
        SELECT teamID
        FROM plays
        WHERE playerID = p1.playerID
    )
    
  4. 最后,将这两个条件应用于步骤 1 中的三角连接的结果。

    SELECT p1.playerID, p1.playerName, p2.playerID, p2.playerName
    FROM player p1
    INNER JOIN player p2 ON p1.playerID < p2.playerID
    WHERE
        NOT EXISTS (
            SELECT teamID
            FROM plays
            WHERE playerID = p1.playerID
    
            EXCEPT
    
            SELECT teamID
            FROM plays
            WHERE playerID = p2.playerID
        )
    AND
        NOT EXISTS (
            SELECT teamID
            FROM plays
            WHERE playerID = p2.playerID
    
            EXCEPT
    
            SELECT teamID
            FROM plays
            WHERE playerID = p1.playerID
        )
    ;
    
于 2013-08-01T13:19:29.377 回答