MySQL使用max选择细节

时间:2011-12-03 12:53:05

标签: mysql group-by greatest-n-per-group

我有一组包含足球管理游戏信息的MySQL表。

表格是:

  • 玩家 - playerID(PK),playerName
  • 匹配 - matchID(PK),matchSeason,matchRound,matchType
  • PlayersMatch - playerID,matchID(comp PK),matchRating,playerForm,playerAge,position(可以为null)

存储在这些表格中的数据与玩家的表现有关。玩家在比赛中进行比赛且具有额定性能(matchRating)。 PlayersMatch中记录了玩家参与的每场比赛,记录了球员当前的状态,比赛表现,比赛时的年龄(出于历史目的)以及他们所处的位置。

现在,目前,我正在使用以下查询列出整个赛季的前10名球员(本赛季整体表现最佳,而不是每轮最佳表现):

SELECT playerID, matchID, playerForm, playerAge, MAX(matchRating)
FROM PlayersMatch
INNER JOIN Matches ON PlayersMatch.matchID = Matches.matchID
WHERE Matches.matchSeason = 35
AND Matches.matchType = 'L'
AND PlayersMatch.position IS NOT NULL
GROUP BY PlayersMatch.playerID
ORDER BY MAX(matchRating) DESC, playerForm ASC

我得到的问题是,当我获得正确的playerID和玩家matchRating时,我得到错误的matchID,表格,年龄和其他信息(即他们来自其他记录)。

我尝试将matchID添加到组中,当我得到正确的信息时,我有重复项,因为它为玩家生成了重复记录(因为playerID和matchID组成了PlayersMatch中的PK)。

非常感谢您对此的帮助。

编辑:经过一些进一步阅读后,我必须正确地编写SQL,并且如果我只有playerID和max(matchRating),则group by才会返回正确的信息 - 在至少是ANSI SQL正确。

在这种情况下,如果我使用max / group by,如何获得该效果的相应匹配详细信息?

编辑2:看起来我有一个有效的查询:

SELECT * FROM PlayersMatch
INNER JOIN 
   (SELECT playerID, MAX(matchRating)
    FROM PlayersMatch p2
    JOIN Matches
      ON p2.matchID = Matches.matchID
    WHERE matchSeason = 35
    AND matchType = 'L'
    AND p2.position IS NOT NULL
    GROUP BY p2.playerID) AS p1
  ON PlayersMatch.playerID = p1.playerID
  AND PlayersMatch.matchRating = p1.matchRating
JOIN Matches m2
  ON PlayersMatch.matchID = m2.matchID
WHERE m2.matchSeason = 35
AND m2.matchType = 'L'
AND PlayersMatch.position IS NOT NULL
ORDER BY matchRating DESC

现在唯一的问题是运行需要21秒。这个查询看起来是否正确?

2 个答案:

答案 0 :(得分:1)

仅基于MatchID在PlayersMatch上添加第二个索引,用于初步资格加入到匹配。在matchSeason的Matches表中添加一个索引并输入。

从您的编辑和发布的数据示例中,我认为这将解析为获得第一个“匹配”,该匹配在相同的“排名”下限定跨越的多个实例。所以,再次,内心最好的MatchRating,因为你的“MAX()”显然正在寻找最高评级。从那以后,它将立即重新加入玩家匹配并获得具有相同评级的该人的第一个匹配ID。最后,要关闭它,我们可以直接加入到人员的名称信息,并根据找到的第一个匹配ID匹配,所以不应该返回重复...最终结果按匹配排名进行排序。

SELECT STRAIGHT_JOIN
      Players.PlayerName,
      M2.*,
      PM.MatchRating,
      PM.PlayerForm,
      PM.PlayerAge,
      PM.Position
   FROM 
      ( select PreMatch.PlayerID,
               PreMatch.MaxMatch,
               MIN( P3.MatchID ) as FirstMatch
           FROM
               ( SELECT 
                    p2.playerID, 
                    MAX(p2.matchRating) MaxMatch
                 FROM 
                    Matches
                       JOIN PlayersMatch P2
                          ON Matches.MatchID = p2.matchID
                         AND P2.Position is not null
                 WHERE 
                        Matches.MatchSeason = 35
                    AND Matches.MatchType = 'L'
                 GROUP BY
                    p2.playerID ) PreMatch

               JOIN PlayersMatch P3
                   ON PreMatch.PlayerID = P3.PlayerID
                  AND PreMatch.MaxMatch = P3.MatchRating
                  AND P3.Position is not null

                  JOIN Matches M2
                     on P3.MatchID = M2.MatchID
                    AND M2.MatchSeason = 35
                    AND M2.MatchType = 'L' 
          GROUP BY
             PreMatch.PlayerID,
             PreMatch.MaxMatch
      ) AS p1

      JOIN Players
         on P1.PlayerID = Players.PlayerID

      JOIN PlayersMatch PM
          on p1.FirstMatch = PM.MatchID 

   ORDER BY 
      p1.MaxMatch DESC

答案 1 :(得分:0)

聚合仅适用于应用它的实际列。它不是基于记录的。它确实选择评级的最大值,但不确定如何聚合其他列。

所以当你有记录时:

player 1 | match 1 | 10 
player 1 | match 2 | 5

并且您按玩家对它们进行分组,它只需要为“匹配”字段选择一个值,但是哪个未定义:它不依赖于其他列中的聚合。

对于你想要做的事,你需要一个子查询:

SELECT p1.playerID, p1.matchID, p1.playerAge, MAX(p1.matchRating)
FROM PlayersMatch P1
JOIN PlayersMatch p2 on p1.id = 
   (SELECT id 
    FROM PlayerMatch p2 
    WHERE p2.playerId = p1.playerId 
    ORDER BY MAX(p2.matchRating) DESC 
    LIMIT 1)
GROUP BY playerID

请注意,我已经为playersmatch-table引入了一个生成的主键(因为我不确定复合键的连接语法和一般有利的单字段人工键。)你仍然可以有一个唯一的约束on(playerID,matchId)。