2011-12-03 56 views
3

我有一套包含足球管理游戏信息的MySQL表。MySQL使用max选择细节

的表是:

  • 选手 - playerID(PK),playerName
  • 相配 - matchID(PK),matchSeason,matchRound,使用MatchType
  • PlayersMatch - playerID,matchID(化合物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 

我得到的问题是,虽然我得到正确的玩家ID和玩家matchRating,我得到了错误的matchID,表单,年龄和其他信息(即他们来自其他记录)。

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

我们非常感谢您的协助。

编辑:一些进一步的阅读后,我一定要正确编写SQL和一个由一群只会返回正确的信息,如果我只是playerID和max(matchRating) - 起码是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秒内运行。这个查询看起来是否正确?

+0

我不同意使用MAX(matchRating)作为整体表现最佳。它不应该使用AVG吗?举例来说,玩家A打了两场比赛,第一场评分为10,第二场评分为2(Avg 6),玩家B打了两场比赛,评分为8,8(Avg 8)。但是你的计算会让玩家A成为最佳表现者。 – ajreal

+0

@ajreal,感谢您的建议,但平均评分不是我想要展示的。我可能会添加一个平均,但在这一点上,我只需要最大。尽管如此,仍然没有解决我的问题。 :P – Cyntech

+0

并非完全:您加入playerId和matchRating,但这并不保证是唯一的(应为matchId)。你是否创建了适当的索引(matchRating,可能matchSeason,matchType和position)。使用'explain'来看看它为什么花费这么长时间。 – Inca

回答

1

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

从您的编辑和发布的数据样本中,我认为这样做可以解决第一个“匹配”问题,即在相同的“排名”下获得跨越多个实例的资格。因此,再次,最内层的获得最佳MatchRating,因为您的“MAX()”显然是在寻找最高评级。从那以后,它将立即重新加入到球员比赛中并获得具有相同评分的该人的FIRST比赛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 
+0

感谢您的回答,它看起来非常好,但我得到了每个球员的所有球员比赛记录。是否可以将限制放在连接上,以限制每个玩家的最佳匹配? – Cyntech

+0

@Cyntech,你可以为每个相应的表中的1或2个玩家做一次数据转储,因为我看不到如何。最内层的查询每个玩家获得一个记录,并且他们的最大匹配率仅适用于35季节,类型L.然后加入到玩家的ID(应该只有1),然后重新加入玩家对他们的ID和MaxMatch的匹配对于同一赛季的第35场比赛评分为L型。因此,除非一个人在同一赛季有多个参赛项目,输入和比赛,否则不应该这样做。 – DRapp

+0

DRapp,正是这个原因。如果一名球员的比赛评分相同(普通发生率),那么每次获得该评分时都会得到一排。因此,我们回到了原来的问题,您无法将matchID添加到联接中,因为它会影响组。示例数据可在此处找到:http://pastebin.com/2ijwPwCc – Cyntech

0

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

所以,当你有记录:

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

,你通过玩家群体他们,就需要挑选一个只为“match'域的值,但哪一个没有定义:它不取决于其他栏目中的总量。

对于你想做什么,你需要一个子查询:

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表生成主键(因为我不知道在加盟语法对于复合键和普遍支持的单场人造键)。你仍然可以在(playerID,matchId)上有一个唯一的约束。

+0

我尝试了你的建议,并用一个生成的密钥(playerID + matchID)来实现它。不幸的是,它需要永远运行 - 即超过20分钟,当我杀死它。 – Cyntech