总有那些个需求,想要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

本文探讨了一种常见的SQL误区,即通过排序和分组获取每个分组的最大值或最小值的方法为何无效,并提供了一个实用的解决方案。通过在查询中添加HAVING 1子句,可以确保正确地获取每个用户最新的支付记录或最高支付金额的订单。

被折叠的 条评论
为什么被折叠?



