选择每位玩家的最佳得分

时间:2012-08-24 09:26:36

标签: mysql select group-by max sql-order-by

我有一个名为Scores的表,其中包含以下列:idplayer_idvalue1value2value3和{{1 }}

该表格包含以下内容:

date

我正在尝试获取一个查询,该查询返回按“value1,value2,value3”中的值排序的每个玩家的最佳高分。 Value1是具有更高重要性,value2中等重要性和value3次要重要性的字段,例如:

+------+-----------+--------+--------+--------+------------+
|  id  | player_id | value1 | value2 | value3 |    date    |
+------+-----------+--------+--------+--------+------------+
|   1  |     1     |   10   |    0   |   0    | 2012-08-02 |
+------+-----------+--------+--------+--------+------------+
|   2  |     2     |   15   |    1   |   0    | 2012-08-03 |
+------+-----------+--------+--------+--------+------------+
|   3  |     3     |    9   |    0   |   0    | 2012-08-04 |
+------+-----------+--------+--------+--------+------------+
|   4  |     1     |   11   |    0   |   0    | 2012-08-05 |
+------+-----------+--------+--------+--------+------------+
|   5  |     2     |   16   |    2   |   0    | 2012-08-06 |
+------+-----------+--------+--------+--------+------------+
|   6  |     2     |   15   |    0   |   0    | 2012-08-07 |
+------+-----------+--------+--------+--------+------------+

我需要的查询的预期结果是:

value1 = 15                              value1 = 15
value2 = 1       is greater than ->      value2 = 0
value3 = 0                               value3 = 1

我正在尝试 MAX DISTINCT GROUP BY 和子查询,但我没有得到正确的结果。基本上它是下一个查询,但选择每个“组”的第一行:

+------+-----------+--------+--------+--------+------------+
|  id  | player_id | value1 | value2 | value3 |    date    |
+------+-----------+--------+--------+--------+------------+
|   5  |     2     |   16   |    2   |   0    | 2012-08-06 |
+------+-----------+--------+--------+--------+------------+
|   4  |     1     |   11   |    0   |   0    | 2012-08-05 |
+------+-----------+--------+--------+--------+------------+
|   3  |     3     |    9   |    0   |   0    | 2012-08-04 |
+------+-----------+--------+--------+--------+------------+

------ 编辑1 -------

eggyal的回答运作正常,但也许,表现不太好。我需要针对大型数据库对其解决方案进行基准测试,以检查响应时间。

我有一个想法(和可能的解决方案)。解决方案包括添加新的布尔列,其中说明该得分是否是该玩家的最佳得分。这样我需要检查当我将新分数添加到数据库中时,新分数是否优于该分区的最佳旧分数,如果是,我需要在旧的最佳分数中将该标记标记为假,并且在新的分数。这为我提供了一种直接检索每个玩家最佳得分的方法(简单查询,如SELECT id, player_id, value1, value2, value3 FROM scores ORDER BY value1 DESC, value2 DESC, value3 DESC )。

------ 编辑2 -------

weicap的回答是最快的解决方案。我不知道为什么,但他的查询比 eggyal的查询快两倍。

------ 编辑3 ------- 我错了,如果查询先前被缓存,weicap的查询会更快,如果不是查询需要十秒或更长时间。在变化中,weicap的答案总是需要300-400ms而不是80.000行。

7 个答案:

答案 0 :(得分:5)

对于每个value,您都可以获得groupwise maximum

SELECT * FROM Scores NATURAL JOIN (
  SELECT player_id, value1, value2, MAX(value3) value3 FROM Scores NATURAL JOIN (
  SELECT player_id, value1, MAX(value2) value2         FROM Scores NATURAL JOIN (
  SELECT player_id, MAX(value1) value1                 FROM Scores
    GROUP BY player_id) t
    GROUP BY player_id) t
    GROUP BY player_id) t
ORDER BY value1 DESC, value2 DESC, value3 DESC

sqlfiddle上查看。

答案 1 :(得分:3)

你可以试试这个

SELECT player_id,
  (SELECT value1
   FROM Scores b where a.player_id=b.player_id  ORDER BY value1 DESC, value2 DESC, value3 DESC limit 1) as value1,
  (SELECT value2
   FROM Scores b where a.player_id=b.player_id  ORDER BY value1 DESC, value2 DESC, value3 DESC limit 1) as value2,
  (SELECT value3
   FROM Scores b where a.player_id=b.player_id  ORDER BY value1 DESC, value2 DESC, value3 DESC limit 1) as value3

FROM Scores a GROUP BY player_id order by value1 DESC, value2 DESC, value3 DESC

或类似

SELECT * FROM Scores a 

where id =(SELECT id
   FROM Scores b where a.player_id=b.player_id  ORDER BY value1 DESC, value2 DESC, value3 DESC limit 1)

GROUP BY player_id order by value1 DESC, value2 DESC, value3 DESC

答案 2 :(得分:2)

尝试在(player_id, value1, value2, value3)上添加索引,然后在此查询中添加:

SELECT
    s.*
FROM 
        Scores AS s
    JOIN
        ( SELECT DISTINCT
              player_id
          FROM 
              Scores
        ) AS p
      ON s.id =
         ( SELECT
               id
           FROM 
               Scores AS b
           WHERE
               b.player_id = p.player_id
           ORDER BY
               value1 DESC, value2 DESC, value3 DESC
           LIMIT 1
         ) 
ORDER BY
    s.value1 DESC, s.value2 DESC, s.value3 DESC ; 

答案 3 :(得分:0)

你的实际得分是:1000,1510,900等......你明白了吗? 它就像十进制数字,其中单个数字的位置很重要。 您可以将3个值转换为单个值以进行分组,您可以在运行中(在查询中右侧)进行估计,也可以预先计算它(在将其写入表之前)。

答案 4 :(得分:0)

您使用的是哪种语言(SQL除外)?如果SQL可以对它进行排序,那将是最简单的,但我不认为这是可能的。如果您使用的是PHP,那么您可以将它放在for循环中,为数组添加索引,例如'bestScore',然后单独检查每个分数,如下所示:

//Extract Data Here
for($outI=0;$outI<count($scores);$outI++){
    $scores[$outI]['bestScore'] = 0;
    for($innI=0;$innI<=3;$innI++){
        if ($scores[$outI]['value' . $innI+1] > $scores[$outI]['bestScore'])
            $scores[$outI]['bestScore'] = $scores[$outI]['value' . $innI+1];
    }
    echo 'The best score for ' . $scores[$outI]['player_id'] . ' was ' . $scores[$outI]['bestScore'] . '.<br />';
}

如果按预期工作,则应列出每位玩家的最佳分数。

答案 5 :(得分:0)

假设你的最大疼痛可以是16,试试这个,

Select Scores.* from Scores, (SELECT player_id,max(17*17*value1+17*value2+value3) 
as max_score  FROM Scores group by player_id)t where 
(17*17*value1+17*value2+value3) = t.max_score and Scores.player_id=t.player_id

答案 6 :(得分:-2)

SELECT * FROM (
SELECT id, player_id, value1, value2, value3, `date`
   FROM scores
   ORDER BY value1 DESC, value2 DESC, value3 DESC
) x 
GROUP BY player_id
order by value1 DESC, value2 DESC, value3 DESC