zua*_*auz 5 mysql sql pivot-table lookup-tables jointable
我正在尝试显示一些简单的计算机游戏结果,并在我的代码中轻松地逐行遍历结果。我希望每场比赛的所有相关数据都在每条记录中,这样我就可以在一行中输出所有数据,例如:
因此,对于一场比赛,有两支球队互相比赛,他们在比赛结束时各获得一个分数。本质上,每场比赛的 games_teams 表最终都有两行。
这是我的架构:

这是我的表数据:

这是我试图实现的输出,以便我可以轻松地遍历结果并将它们输出到页面上:

我设法通过一些可怕的 SQL 和许多子查询来实现这一点:
SELECT games.game_id, game_name, game_duration,
(SELECT team_id FROM games_teams WHERE games.game_id = games_teams.game_id LIMIT 0, 1) AS team_id_a,
(SELECT team_id FROM games_teams WHERE games.game_id = games_teams.game_id LIMIT 1, 1) AS team_id_b,
(SELECT teams.team_name FROM games_teams INNER JOIN teams ON games_teams.team_id = teams.team_id WHERE games.game_id = game_id LIMIT 0, 1) AS team_name_a,
(SELECT teams.team_name FROM games_teams INNER JOIN teams ON games_teams.team_id = teams.team_id WHERE games.game_id = game_id LIMIT 1, 1) AS team_name_b,
(SELECT team_score FROM games_teams WHERE games.game_id = games_teams.game_id LIMIT 0, 1) AS team_score_a,
(SELECT team_score FROM games_teams WHERE games.game_id = games_teams.game_id LIMIT 1, 1) AS team_score_b
FROM games
Run Code Online (Sandbox Code Playgroud)
该方法的问题在于它会很慢并且无法扩展。我还需要从 games_teams 表中提取其他游戏统计数据,以便获得更多子查询。
我尝试的另一种方法是:

我使用以下 SQL 实现了这一点:
SELECT games.game_id, game_name, game_duration, teams.team_id, team_name, team_score
FROM games
INNER JOIN games_teams ON games.game_id = games_teams.game_id
INNER JOIN teams ON games_teams.team_id = teams.team_id
Run Code Online (Sandbox Code Playgroud)
现在这种方式将更难在代码中进行 foreach,因为每个游戏的相关数据在两个不同的记录中。我必须构建该行的第一部分,然后进入下一个循环迭代并打印下一部分。然后为下一场比赛重新开始,我试图在一行上显示所有信息,例如:
A队(45分)vs B队(55分),比赛时长:5分钟
所以这就是为什么我认为如果所有内容都在一张唱片上会更容易。如果我需要在 games_teams 表中的更多列,有没有一种方法可以很好地实现这一点?
如果您需要重新创建它,这里有一个带有数据库代码的 pastebin 链接。
非常感谢任何帮助,谢谢!
您需要两次加入 games_teams 和团队,例如:
SELECT ga.game_id
, ga.game_name
, ga.game_duration
, t1.team_name, gt1.team_score
, t2.team_name, gt2.team_score
FROM games ga
JOIN games_teams gt1 ON gt1.game_id = ga.game_id
JOIN games_teams gt2 ON gt2.game_id = ga.game_id
JOIN teams t1 ON t1.team_id = gt1.team_id
JOIN teams t2 ON t2.team_id = gt2.team_id
WHERE gt1.team_id < gt2.team_id
;
Run Code Online (Sandbox Code Playgroud)
挤出 {games_teams * team} 子连接并引用它两次的干净方法是将其放入 CTE 中:(不幸的是 mysql 不支持 CTE)
WITH gtx AS (
SELECT gt.game_id
, gt.team_score
, te.team_id
, te.team_name
FROM games_teams gt
JOIN teams te ON te.team_id = gt.team_id
)
SELECT ga.game_id
, ga.game_name
, ga.game_duration
, g1.team_name, g1.team_score
, g2.team_name, g2.team_score
FROM games ga
JOIN gtx g1 ON g1.game_id = ga.game_id
JOIN gtx g2 ON g2.game_id = ga.game_id
WHERE g1.team_id < g2.team_id
;
Run Code Online (Sandbox Code Playgroud)
结果:
game_id | game_name | game_duration | team_name | team_score | team_name | team_score
---------+-----------+---------------+-----------+------------+-----------+------------
1 | Game A | 300 | Team A | 45 | Team B | 55
2 | Game B | 258 | Team C | 60 | Team D | 65
(2 rows)
Run Code Online (Sandbox Code Playgroud)