在MySQL中返回MAX函数的相应列

时间:2011-06-18 23:03:10

标签: mysql sql

我有一张桌子,其中包含保龄球中心球员的分数。每行都有一些关于哪个玩家击败游戏,玩哪个联赛,日期,单个游戏得分,车道号等的数据。

我想要做的就是让每一条赛道上的最佳系列赛(三场比赛)得分(以及在哪个联赛和哪个日期...基本上整排)。

到目前为止我所拥有的是

SELECT PlayerID, LaneNumber, MAX(Series)
  FROM (SELECT Season, LeagueName, LaneNumber, WeekNumber, PlayerID, Date, SUM(Score) AS Series 
          FROM Scores
      GROUP BY Season, LeagueName, WeekNumber, PlayerID)
GROUP BY LaneNumber

这是有效的,因为我为每一条车道获得了最好的三个游戏,这实际上就是我想要的,但是包含PlayerID的另一个字段实际上并不正确。

在我的表格中,24号车道(从SUM(得分)和GROUP BY赛季,LeagueName,WeekNumber,PlayerID获得)的最高分为848,由玩家ID为36的玩家进行。

我得到的是24号通道848(这是正确的),但PlayedID返回是3166.同样的事情发生在每一条车道上。 (因为,我得到了明显错误的PlayerID。如果我在第一个选择中有其他列,那么它们也是错误的)

4 个答案:

答案 0 :(得分:3)

您违反了GROUP BY的语义。

使用GROUP BY时,它仅对您按(例如SELECT)分组的LaneNumber列和其他列的汇总函数(例如MAX(Series))有意义。选择其他任何内容(在您的情况下为PlayerID)没有意义,因为您没有在共享相同LaneNumber的人中指定您想要的玩家ID。< / p>

遗憾的是,默认情况下,MySql会在不报告错误的情况下执行此操作,并且它将返回它为违规列选择的任何值。在您的情况下,这意味着您将获得在指定分组中包含的玩家ID“随机”选择。

您也在内部查询中执行此操作,您可以在其中选择LaneNumberWeekNumberDate

<强>解决方案

需要重写查询,但首先需要仔细指定要获得的结果。您是否想要每个系列(以及任何通道)的最佳播放器和相关数据?对于每个系列和车道分开?这个问题的答案将决定GROUP BY所需的内容,以及查询的内容。

答案 1 :(得分:2)

请看这里:http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html

尝试在一个查询中完成所有操作可能会变得混乱,但基本上,您希望像以前一样生成系列数据:

SELECT Season, LeagueName, LaneNumber, WeekNumber, PlayerID, Date, SUM(Score) AS Series 
      FROM Scores
  GROUP BY Season, LeagueName, WeekNumber, PlayerID

然后,您需要添加一个子句:WHERE Series=,然后要获得正确的值,而不是从此表中获取max系列值,您需要执行另一个选择,获得最大值(系列) )其中LaneNumber在两个表中都是相同的。我会为你编写代码,但我对MySQL的能力不够自信!

答案 2 :(得分:2)

如@Jon所述,您需要删除那些不适用于特定人的元素。然后,由于@Ord有最接近的样本,最好将结果预先查询到一个单独的表中(不是临时的,因为MySQL会在第二个查询中尝试从自联接中查询自身时阻塞它)。 / p>

所以,对我来说(几年前曾经是联盟投球手),而且你的内容遍及所有联赛,同一时间的同一条赛道永远不会有两个不同的联赛,但是,整整一个晚上,你可以有不同的联赛开始不同的时间...例如6-8:30,8:45-11 ...所以联盟和日期的分组将起作用。但是,您需要将播放器作为组的一部分来获取它们各自的SUM()值。

为了帮助澄清答案,我假设我有以下数据。这些数据仅代表单个车道,一周,一个赛季,但每个联赛有两个联赛和3名球员(仅用于显示结果和限制内容)

League   Player   Score
L1       1        223
L1       1        218
L1       1        204
L1       2        187
L1       2        201
L1       2        189
L1       3        148
L1       3        152
L1       3        158

L2       4        189
L2       4        195
L2       4        192
L2       5        182
L2       5        199
L2       5        209
L2       6        228
L2       6        234
L2       6        218


CREATE TABLE SeriesScores2
SELECT 
      Season, 
      LeagueName, 
      LaneNumber, 
      WeekNumber, 
      PlayerID, 
      SUM(Score) AS Series 
   FROM 
      Scores
   GROUP BY 
      Season, 
      LeagueName, 
      LaneNumber, 
      WeekNumber, 
      PlayerID;

第一个查询(上面)将创建将为所有玩家创建所有星期,所有联盟等的系列。假设现在我已经添加了共同的季节,车道,周也

Season   League   Lane   Week   Player   Series
1        L1       1      1      1        645
1        L1       1      1      2        577
1        L1       1      1      3        458
1        L2       1      1      4        576
1        L2       1      1      5        590
1        L2       1      1      6        680

这为我们提供了确定max()的前提,否则我们必须在自身内部和外层重复查询,使其比预先聚合更复杂。

现在,上面的永久表(可以在获得结果后删除),查询FIRST(PreQuery)获得最高分PER PERAGUE PER LANE ...例如:男子联赛通常会有更高的系列赛分数比女性......与不同年龄组相似。所以,男子联赛第1的最高分和女子联赛第1的最高分等等。最高分通常在整个赛季的单周确定,而不是每周最高系列赛。

现在,PreQuery“ss”的别名就在赛季,联赛,车道和最大系列赛上。一旦知道了这一点,就自行参加系列赛得分,以获得该赛道上得分最高的WHO DID并拉出谁及其发生的那一周

select
      ss.season, 
      ss.leaguename, 
      ss.lanenumber, 
      ss.highestSeries, 
      ss2.PlayerID, 
      ss2.WeekNumber
   from
      ( select season, leaguename, lanenumber, max( series ) highestSeries
           from SeriesScores2
           group by season, leaguename, lanenumber ) ss
      join SeriesScores2 ss2
         on ss.Season = ss2.Season
        and ss.LeagueName = ss2.LeagueName
        and ss.LaneNumber = ss2.LaneNumber
        and ss.HighestSeries = ss2.Series

现在,从上面的查询...让我们分解它。如果我们采取内在的“ss”预先查询

  ( select season, leaguename, lanenumber, max( series ) highestSeries
       from SeriesScores2
       group by season, leaguename, lanenumber ) ss

我们将获得每个联赛的最高得分(例如:男子联赛与女子联赛同一周,同一夜,同一车道,我们发现(下方),仅仅是最大值,但没有世界卫生组织或什么周,只是最高级别的系列赛,不论周或人。所以这成为JOIN的基础回到预先汇总的表“SeriesScores2”,但在这里,我们有最高的系列分数,以确保我们找到正确的人

Season  League   Lane   HighestSeries
1       L1       1      645
1       L2       1      680

To refresh preaggregation
Season   League   Lane   Week   Player   Series
1        L1       1      1      1        645    <-- Join finds THIS entry League 1
1        L1       1      1      2        577
1        L1       1      1      3        458
1        L2       1      1      4        576
1        L2       1      1      5        590
1        L2       1      1      6        680    <-- Join finds THIS entry League 2

所以,我的原始查询确实有效,因为我在发布前测试了它们。除非专栏名称不正确或其他什么,否则我不知道你对你的打嗝。至于“日期”栏目,我并不特别在意,因为你有可用的周数,这对应于保龄球周,并且无论如何都是1:1的关系。可以将日期列添加到预聚合SeriesScores2中,并在获取人员ID和周时拉出。 (除非一个联盟在同一个星期的多个晚上投球,然后你需要明确的日期)。

希望这能澄清您的问题/意见。

答案 3 :(得分:1)

好的,尝试实际编写我想到的MySQL代码(我无法抗拒......):

CREATE TEMPORARY TABLE SeriesScores
SELECT Season, LeagueName, LaneNumber, WeekNumber, PlayerID, SUM(Score) AS Series 
    FROM Scores
    GROUP BY Season, LeagueName, WeekNumber, PlayerID;

这个位只会获得每个系列的分数,正如您在自己的MySQL代码中指定的那样。唯一不同的是我没有选择日期,因为我们不按它分组,它的值将是随机的。然后:

SELECT PlayerID, LaneNumber, Series
    FROM SeriesScores s1
    WHERE  Series=(SELECT MAX(s2.Series)
          FROM SeriesScores s2
          WHERE s1.LaneNumber = s2.LaneNumber);

这一位只是从SeriesScores中选择你需要的东西,并且只考虑系列分数是那条泳道最大值的行。

这对你有用吗?