总有那些个需求,想要group by分组数据,但又想规定获取其中某个条件最大/最小的数据。本人也遇到这么个需求,于是上网搜了搜,发现大多都是这样的一个答案:先将要分组的数据按照条件进行排序,之后获取其数据集来进行分组。这种方法很常见,但是广大网友的眼睛是雪亮的:这种方式是不行的!
本人也是看到这篇文章有感而发:group by分组后获得每组中时间最大的那条记录
接下来让我们来试试看,这种方式到底是不是真的不可取
首先,假设有这样一个订单表(假设的,真的就是拿来随便测试的)
CREATE TABLE `order_test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL COMMENT '下单用户id',
`pay_money` int(11) NOT NULL DEFAULT '0' COMMENT '支付金额(单位为分)',
`pay_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '支付时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
再来捏造这样几条数据:
id | user_id | pay_money | pay_time |
---|---|---|---|
1 | 1 | 1000 | 2020-06-01 00:00:00 |
2 | 1 | 2000 | 2020-06-02 00:00:00 |
3 | 1 | 3000 | 2020-06-03 00:00:00 |
4 | 2 | 1500 | 2020-06-01 00:00:00 |
5 | 2 | 2500 | 2020-06-02 00:00:00 |
6 | 2 | 3500 | 2020-06-03 00:00:00 |
7 | 3 | 1250 | 2020-06-01 00:00:00 |
8 | 3 | 2250 | 2020-06-02 00:00:00 |
9 | 3 | 3250 | 2020-06-03 00:00:00 |
接下来按照网上流传方法来试试看,获取各个用户最新支付的订单:
- 先对用户id进行正序排序,再对支付时间进行倒序排序
- 将第1步查询的数据集当做临时表,已经被排好序了
- 对临时表进行group by分组,得到最终结果
SELECT
*
FROM
( SELECT * FROM `order_test` ORDER BY user_id ASC, pay_time DESC ) A
GROUP BY
user_id
可以明显的看到,结果中支付时间都是最旧的,根本不是我们想要的结果!
那么怎样才能拿到我们真正想要的结果呢?
强大的网友提供了这样一个方法:在刚才那条SQL上加一个HAVING 1
就可以了。
什么操作?这么神奇的?来来试试
SELECT
*
FROM
( SELECT * FROM `order_test` HAVING 1 ORDER BY user_id ASC, pay_time DESC ) A
GROUP BY
user_id
ps:user_id ASC
是可以不用写的
膜拜大佬!!!
虽然不懂原理但是真的成功了,实测可用!大佬牛批!(大佬就在本文参考文章的评论中,有需要的同学可以去膜拜膜拜,有考必过)
当然,不只是支付时间可以用这种方式,其他字段也是可以使用的
比如:获取各个用户支付金额最多的一条订单
SELECT
*
FROM
( SELECT * FROM `order_test` HAVING 1 ORDER BY pay_money DESC ) A
GROUP BY
user_id