mysql 分组取最大值的同时获取包含最大值的行的其他字段

时间:2021-10-01 14:47:32

假设有表如下:

+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
| 0001 | A | 3.45 |
| 0001 | B | 3.99 |
| 0002 | A | 10.99 |
| 0003 | B | 1.45 |
| 0003 | C | 1.69 |
| 0003 | D | 1.25 |
| 0004 | D | 19.95 |
| 0004 | C | 2.97 |
+---------+--------+-------+

按article分组,求最大price,同时希望取出某article最大price时的dealer。dealer不是group by字段,标准sql里不能直接分组的同时获得该字段值。

解决办法
把dealer拼串在price后面,但是又要保证拼出来的串在比较大小时跟直接用price比较大小是一致的。

select
article,
max(concat(length(floor(price)), '-', price, '-', dealer)) as price_dealer
from shop
group by article;

结果:

+---------+--------------+
| article | price_dealer |
+---------+--------------+
| 0001 | 1-3.99-B |
| 0002 | 2-10.99-A |
| 0003 | 1-1.69-C |
| 0004 | 2-19.95-D |
+---------+--------------+

之后可以在程序中以'-'为分隔符进行拆分或者直接在sql中利用substring_index函数拆分:

select
article,
substring_index(
substring_index(
max(concat(length(floor(price)),'-', price, '-', dealer)),
'-',
2),
'-',
-1) as price,
substring_index(
max(concat(length(floor(price)), '-', price, '-', dealer)),
'-',
-1) as dealer
from shop
group by article;

结果:

+---------+-------+--------+
| article | price | dealer |
+---------+-------+--------+
| 0001 | 3.99 | B |
| 0002 | 10.99 | A |
| 0003 | 1.69 | C |
| 0004 | 19.95 | D |
+---------+-------+--------+

由于max()函数对字符串是按ascii排序而不是数值排序,这样'2.97'会大于'19.95'。为了得到正确的比较,我们在拼串的前面加上price整数部分的长度。

讨论:
mysql官方文档里给出了用lpad拼串排序的例子:

SELECT article,
SUBSTRING( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 7) AS dealer,
0.00+LEFT( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 6) AS price
FROM shop
GROUP BY article;

运行结果和我们上面用的方法的结果一样。这种方法比较简短一些。不过需要price小数部分定长和预先知道price和dealer的最大长度。