带细节的MySQL分组

带细节的MySQL分组,mysql,sql,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脚本,它可以收回用户在一场比赛中赢得的最多分数,并在结果中包含比赛id——换句话说 user_i

我有一张像这样的桌子

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脚本,它可以收回用户在一场比赛中赢得的最多分数,并在结果中包含比赛id——换句话说

user_id, match_id, max_points_won
1          12          80
2          8           10
3          2           25
当然,如果我不需要火柴id,我可以

select user_id, max(points_won)
from table
group by user_id
但是,一旦我将match_id添加到select and group by,我就会为每个匹配创建一行,如果我只将match_id添加到select而不是group,那么它将无法正确地与所获得的分数关联

理想情况下,我也不想做以下事情,因为这样做并不特别安全,例如,如果用户在多场比赛中赢得了相同数量的分数

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
对于这个问题,还有其他更优雅的选项吗?

您可以使用以下查询:

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
编辑:仅适用于postgresql、sql server、oracle

您可以使用行号:

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的答案或者这个


在您的示例中,您将结果集按用户进行分区,然后按点数排序,以首先获得最高的获胜点数

我认为您可以通过在内部查询中添加限制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

这比MySQL中需要的要难。有一种方法有点老套,但它在大多数情况下都有效。这就是组concat/substring索引技巧:

组concat将所有匹配ID连接在一起,按点降序排列。然后子字符串_索引取第一个

两个重要的警告:

无论内部类型如何,结果表达式都具有字符串类型。 组_concat使用一个内部缓冲区,默认情况下,其长度为1024个字符。此默认长度可以更改。
很抱歉,devoh-但我在运行此程序时查看了与您的MySQL服务器版本相对应的手册-可能是其他版本的有效解决方案,当然我很糟糕。我不知道mysql不支持Sql Server这样的行数,Oracle或Postgre.Thank algojava-唯一的问题是,我认为我最初的示例查询可能有缺陷-我在运行时得到了一个引用“max_points_won”不支持对组函数的引用错误感谢Giorgos-这是一个非常好的解决方案,但我可能对连接回来自的points_won感到不必要的紧张最大值,例如,如果在同一个最大点上有多条记录Hanks Gordon-hack与否,这正是我想要的!
select user_id, max(points_won),
       substring_index(group_concat(match_id order by points_won desc), ',', 1) 
from table
group by user_id;