簡體   English   中英

涉及多個表的復雜SQL查詢

[英]Complicated SQL Query involving multiple tables

在這個查詢中,我必須列出一對玩家ID和玩家名稱的球員,他們為同一支球隊效力。如果一名球員為3支球隊效力,則另一支球員必須參加完全相同的3支球隊。 不能少,不多了。 如果兩名球員目前不參加任何球隊,他們也應該被包括在內。 查詢應該返回(playerID1,playername1,playerID2,playerName2)而沒有重復,例如如果玩家1信息在玩家2之前出現,則不應該有另一個玩家2信息在玩家1之前出現的元組。

例如,如果玩家A為洋基隊和紅襪隊隊員比賽,而隊員隊員為洋基隊隊員,紅襪隊隊員和道奇隊隊員隊效力,我就不應該參加比賽。 他們都必須為洋基隊和紅襪隊效力,而不是其他人。 現在,如果玩家為同一個團隊玩游戲,此查詢會找到答案。

 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.....

在此之后,我被困在如何接近它。 有關如何解決此問題的任何提示。 謝謝你的時間。

我認為最簡單的方法是將團隊連接在一起,然后加入結果。 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和匹配來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值意味着所有團隊都匹配。

這是對你前一個問題答案的改編。

  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 ) ; 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM