【问题标题】:SQL Soccer match exercise - adding columns, details and improved rankingSQL 足球比赛练习 - 添加列、详细信息和改进的排名
【发布时间】:2021-09-22 00:03:42
【问题描述】:

我最近开始练习 SQL,之前有一些 MySQL 经验,仅用于网站数据库管理,但没有实际的 SQL 查询构造。 之前已经询问过此练习的变体,但我想扩大以前解决方案的范围。 这是一个足球(足球)得分练习,构建了一个小联盟中不同比赛的汇总结果表。

TL;DR 我设法获得了部分解决方案,但想在决赛桌中再添加 3 列,并改进计算最终排名的方式。

我创建了一个包含 4 个团队的表格,并为每个团队分配了一个 ID:

CREATE TABLE Teams AS
  SELECT 100 AS TEAM_ID, 'PUMP' AS TEAM UNION ALL
  SELECT 200, 'UP' UNION ALL
  SELECT 300, 'THE' UNION ALL
  SELECT 400, 'JAM';

输出是:

SELECT * FROM Teams

还有一张桌子:

TEAM_ID TEAM
100 PUMP
200 UP
300 THE
400 JAM

然后我创建了第二个表格,其中包含游戏的比赛得分:

CREATE TABLE Matches AS
SELECT 1 AS MATCH_ID, 100 AS HomeTeam, 200 AS AwayTeam, 2 AS HomeScore, 0 AS AwayScore UNION ALL 
SELECT 2, 300, 400, 1, 1 UNION ALL
SELECT 3, 400, 100, 0, 1 UNION ALL
SELECT 4, 300, 200, 2, 3 UNION ALL
SELECT 5, 200, 400, 0, 0 UNION ALL
SELECT 6, 300, 100, 1, 0;

接收:

MATCH_ID HomeTeam AwayTeam HomeScore AwayScore
1 100 200 2 0
2 300 400 1 1
3 400 100 0 1
4 300 200 2 3
5 200 400 0 0
6 300 100 1 0

我能够创建一个总分表,显示每支球队的联赛总分,并遵循以下指点规则:

  • 球队获胜得 3 分,
  • 球队打平得 1 分,
  • 队伍输了得 0 分
WITH cteHomePoints AS (SELECT HomeTeam AS Team,
                              CASE
                                WHEN HomeScore > AwayScore THEN 3
                                WHEN HomeScore = AwayScore THEN 1
                                ELSE 0
                              END AS Points
                         FROM Matches),
     cteAwayPoints AS (SELECT AwayTeam AS Team,
                               CASE
                                 WHEN AwayScore > HomeScore THEN 3
                                 WHEN AwayScore = HomeScore THEN 1
                                 ELSE 0
                               END AS Points
                          FROM Matches),
     cteAllPoints AS (SELECT Team, Points FROM cteHomePoints
                      UNION ALL
                      SELECT Team, Points FROM cteAwayPoints)
SELECT t.TEAM_ID, t.TEAM, COALESCE(SUM(ap.POINTS), 0) AS TOTAL_POINTS
  FROM Teams t
  LEFT OUTER JOIN cteAllPoints ap
    ON ap.TEAM = t.TEAM_ID
  GROUP BY  t.TEAM_ID, t.TEAM
  ORDER BY COALESCE(SUM(POINTS), 0) DESC, t.TEAM_ID

生成此表:

TEAM_ID TEAM TOTAL_POINTS
100 PUMP 6
200 UP 4
300 THE 4
400 JAM 2

不过,有两件事我想完成:

  1. 我想在决赛桌中再添加 3 列以显示给每个团队:
  • GoalsScored
  • 收到的目标
  • 差异(得分和接受之间)
  1. 球队位置由积分数决定,如果并列,则位置由更好的“净胜球”决定,即进球数减去获得的进球数。这会影响最终排名(第二名和第三名会互换位置)。

我尝试了几种不同的方式进行调整,例如添加

     cteHomeScore AS (SELECT HomeTeam AS Team,
                             END AS Scored
                         FROM Matches),
     cteAwayScore AS (SELECT AwayTeam AS Team,
                             END AS Received
                         FROM Matches),                               
     cteAllScored AS (SELECT Team, Scored FROM cteHomeScore
                      UNION ALL
                      SELECT Team, Received FROM cteAwayScore),    

但我似乎无法破解它。

任何帮助将不胜感激:)

【问题讨论】:

  • 您可以将得分、获得的目标和差异添加到您现有的得分确定 cte 中,然后以相同的方式进行总结。之后,您可以订购您想要的结果。
  • @Parfait GoalsScored 是球队在所有比赛中的总进球数(来自 HomeScore 和 AwayScore)。 GoalsReceived 是球队的对手在比赛中的总进球数(来自 HomeScore 和 AwayScore)。例如,团队 PUMP (ID 100),打进 3 个进球 (GoalsScored=3),并获得 1 个进球 (GoalsReceived=1)。

标签: mysql sql


【解决方案1】:

这是一种不同的方法:

SELECT T.TEAM_ID, T.TEAM, 
        SUM(points) AS Points, 
        SUM(HomeScore) AS 'Goals Scored', 
        SUM(AwayScore) AS 'Goals Received',
        SUM(HomeScore-AwayScore) 'GoalDiff'
 FROM 
Teams T 
LEFT JOIN
(SELECT HomeTeam AS Team, HomeScore, AwayScore,
       CASE WHEN HomeScore > AwayScore THEN 3
            WHEN HomeScore = AwayScore THEN 1
            ELSE 0
            END AS Points
FROM Matches UNION ALL
SELECT AwayTeam,  AwayScore, HomeScore,
       CASE WHEN AwayScore > HomeScore THEN 3
            WHEN AwayScore = HomeScore THEN 1
            ELSE 0
            END
FROM Matches) mm
ON T.TEAM_ID=mm.team
GROUP BY T.TEAM_ID, T.TEAM
ORDER BY Points DESC, GoalDiff DESC

更新:我已将SELECT 部分的HomeScoreAwayScore 的顺序从HomeScore, AwayScore 切换为AwayScore, HomeScore,并将@ 部分的HomeScore > AwayScore 切换为AwayScore > HomeScore UNION ALL 子查询中第二个查询的 987654331@ 表达式,这是 @JanezKuhar 非常好的观察结果。

This is the extended fiddle inclusive of the additional data suggested

【讨论】:

    【解决方案2】:

    考虑包含所需聚合和条件聚合的自联接(而不是 UNION)。如评论所述,根据需要调整计算:

    WITH aggHome AS (
         SELECT HomeTeam AS Team
              , SUM(CASE
                      WHEN HomeScore > AwayScore THEN 3
                      WHEN HomeScore = AwayScore THEN 1
                      ELSE 0
                    END) AS HomeSumPoints
              , SUM(HomeScore) As HomeSumScores
              , SUM(AwayScore) As HomeSumReceived
         FROM Matches
         GROUP BY HomeTeam
    ),
        aggAway AS (
         SELECT AwayTeam AS Team
              , SUM(CASE
                      WHEN AwayScore > HomeScore THEN 3
                      WHEN AwayScore = HomeScore THEN 1
                      ELSE 0
                    END) AS AwaySumPoints
              , SUM(AwayScore) As AwaySumScores
              , SUM(HomeScore) As AwaySumReceived
         FROM Matches
         GROUP BY AwayTeam
    )
    
    SELECT h.Team
         , HomeSumPoints + AwaySumPoints As TotalPoints
         , HomeSumScores + AwaySumScores As GoalsScores
         , HomeSumReceived + AwaySumReceived As GoalsReceived
         , (HomeSumScores + AwaySumScores) - 
           (HomeSumReceived + AwaySumReceived) As Difference
    FROM aggHome h
    LEFT JOIN aggAway a
      ON h.Team = a.Team
    

    注意:如果某些球队打主场比赛或打客场比赛,请将INNER JOIN替换为 MySQL 等价的SQL 的FULL OUTER JOIN

    【讨论】:

    • 这很棒 - 而且更加精简。但是,我在运行时收到错误 Unknown column 'GoalsScores' in 'field list'。有一支球队(300人)只打主场比赛,是不是因为这个?不幸的是,FULL OUTER JOIN 似乎不起作用
    • 看起来和GoalsScores - GoalsReceived As Difference行有关
    • MySQL 不支持FULL OUTER JOIN(因此等价)。搜索此类解决方案。但是对那一个团队使用LEFT JOIN。我认为 MySQL 允许使用派生列。继续并重复表达式。见编辑。
    • 感谢@Parfait,它似乎可以解决问题 - 我之前使用 LEFT JOIN 尝试过,但由于我的拼写错误,它不起作用,但现在可以了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 2021-01-20
    • 1970-01-01
    相关资源
    最近更新 更多