MySQL分组详细信息

时间:2017-02-11 12:11:50

标签: mysql sql

我有一张看起来像这样的桌子......

user_id, match_id, points_won
1          14         10
1          8          12
1          12         80
2          8          10
3          14         20
3          2          25

我想写一个MYSQL脚本,它可以回退用户在一场比赛中赢得的最多分数,并在结果中包含match_id - 换句话说......

user_id, match_id, max_points_won
1          12          80
2          8           10
3          2           25

当然,如果我不需要match_id,我可以做......

select user_id, max(points_won)
from table
group by user_id

但是一旦我将match_id添加到"选择" " group by"我每场比赛都有一行,如果我只将match_id添加到"选择" (而不是""组)然后它不能正确地与points_won相关联。

理想情况下,我不想做以下事情,因为它感觉不是特别安全(例如,如果用户在多场比赛中获得相同数量的分数)......

SELECT t.user_id, max(t.points_won) max_points_won
, (select t2.match_id 
   from table t2 
   where t2.user_id = t.user_id 
   and t2.points_won = max_points_won) as 'match_of_points_maximum'
FROM table t
GROUP BY t.user_id

这个问题还有更优雅的选择吗?

4 个答案:

答案 0 :(得分:2)

这比在MySQL中需要的更难。一种方法有点像黑客,但它在大多数情况下都有效。这是group_concat() / substring_index()诀窍:

select user_id, max(points_won),
       substring_index(group_concat(match_id order by points_won desc), ',', 1) 
from table
group by user_id;

group_concat()将所有match_id连接在一起,按降序排列。然后substring_index()接受第一个。

两个重要的警告:

  • 无论内部类型如何,生成的表达式都具有字符串类型。
  • group_concat()使用内部缓冲区,其长度(默认情况下)为1,024个字符。可以更改此默认长度。

答案 1 :(得分:1)

您可以使用查询:

select user_id, max(points_won) 
from table
group by user_id

作为派生表。将其加入原始表可以获得您想要的结果:

select t1.user_id, t1.match_id, t2.max_points_won 
from table as t1
join (
    select user_id, max(points_won) as max_points_won
    from table
    group by user_id
) as t2 on t1.user_id = t2.user_id and t1.points_won = t2.max_points_won

答案 2 :(得分:0)

编辑:仅适用于postgresql,sql-server,oracle

您可以使用row_number:

SELECT USER_ID, MATCH_ID, POINTS_WON
FROM
(
    SELECT user_id, match_id, points_won, row_number() over (partition by user_id order by points_won desc) rn
    from table
) q
where q.rn = 1

对于类似的功能,请查看Gordon Linoff的答案或article

在您的示例中,您按照每个用户对结果集进行分区,然后通过points_won desc命令首先获得最高获胜点。

答案 3 :(得分:0)

我认为您可以通过在内部查询中添加限制1来优化查询。

SELECT t.user_id, max(t.points_won) max_points_won
, (select t2.match_id 
   from table t2 
   where t2.user_id = t.user_id 
   and t2.points_won = max_points_won limit 1) as 'match_of_points_maximum'
FROM table t
GROUP BY t.user_id