MySQL 5.7 按value1分组取每组value2最高对应行的SQL实现
MySQL 5.7 分组取最大值对应整行的实现
MySQL 5.7 默认开启ONLY_FULL_GROUP_BY严格语法校验,直接用GROUP BY value1搭配聚合函数是无法直接带出value3字段的,会触发语法报错,下面是两种可直接落地、结果和预期完全匹配的写法:
写法1:关联聚合子查询(性能最优,适合大表场景)
先聚合算出每个value1分组里的最大value2值,再和原表做双字段等值关联,匹配出对应整行数据,不会触发严格模式校验,也不需要对全表数据做额外排序,大表上的执行效率远高于其他实现方式:
SELECT t.value1, t.value2, t.value3 FROM `values` t INNER JOIN ( SELECT value1, MAX(value2) AS max_val2 FROM `values` GROUP BY value1 ) group_max ON t.value1 = group_max.value1 AND t.value2 = group_max.max_val2;
注意点:如果同一
value1分组下存在多行value2等于最大值,这种写法会返回所有匹配的行。如果需要强制只保留单行,可以根据业务补充额外的排序去重规则。
写法2:用户变量实现组内行排名(扩展性更强)
如果后续需要调整排序规则(比如同value2下取value3最大的行、或者取最早录入的行),可以用MySQL 5.7原生支持的会话变量给组内行打排名标记,直接过滤排名为1的行即可:
SELECT value1, value2, value3 FROM ( SELECT raw.*, -- 相同value1的组内行号累加,组切换时行号归1 @row_rank := IF(@last_group = raw.value1, @row_rank + 1, 1) AS rn, @last_group := raw.value1 FROM `values` raw, -- 初始化会话变量 (SELECT @row_rank := 0, @last_group := '') var_init -- 先按分组字段、排序字段排好序,保证排名计算逻辑正确 ORDER BY raw.value1, raw.value2 DESC ) ranked WHERE rn = 1;
两种写法执行后得到的结果完全匹配预期输出:
| value1 | value2 | value3 |
|---|---|---|
| foo | 12 | anything3 |
| bar | 18 | anything5 |
| baz | 100 | something0 |
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

