mysql group by 组内排序方法

mysql的group by语法可以根据指定的规则对数据进行分组,分组就是将一个数据集划分成若干个小区域,然后再针对若干个小区域进行数据处理。本文将介绍mysql使用group by分组时,实现组内排序的方法。

mysql的group by语法可以对数据进行分组,但是分组后的数据并不能进行组内排序。


例如一个评论表有多个用户评论,需要获取每个用户最后评论的内容。

创建测试数据表及数据

CREATE TABLE `comment` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `content` varchar(200) NOT NULL,
  `addtime` datetime NOT NULL,
  `lastmodify` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `addtime` (`addtime`),
  KEY `uid_addtime` (`user_id`,`addtime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO comment (id, user_id, content, addtime, lastmodify) VALUES
(1, 1, ‘评论1’, ‘2017-05-17 00:00:00’, ‘2017-05-17 00:00:00’),
(2, 1, ‘评论2’, ‘2017-05-17 00:00:01’, ‘2017-05-17 00:00:01’),
(3, 2, ‘评论1’, ‘2017-05-17 00:00:02’, ‘2017-05-17 00:00:02’),
(4, 2, ‘评论2’, ‘2017-05-17 00:00:03’, ‘2017-05-17 00:00:03’),
(5, 3, ‘评论1’, ‘2017-05-17 00:00:04’, ‘2017-05-17 00:00:04’),
(6, 1, ‘评论3’, ‘2017-05-17 00:00:05’, ‘2017-05-17 00:00:05’),
(7, 4, ‘评论1’, ‘2017-05-17 00:00:06’, ‘2017-05-17 00:00:06’),
(8, 4, ‘评论2’, ‘2017-05-17 00:00:07’, ‘2017-05-17 00:00:07’),
(9, 4, ‘评论3’, ‘2017-05-17 00:00:08’, ‘2017-05-17 00:00:08’),
(10, 4, ‘评论4’, ‘2017-05-17 00:00:09’, ‘2017-05-17 00:00:09’),
(11, 3, ‘评论2’, ‘2017-05-17 00:00:10’, ‘2017-05-17 00:00:10’);

select * from comment;
+----±--------±--------±--------------------±--------------------+
| id | user_id | content | addtime | lastmodify |
+----±--------±--------±--------------------±--------------------+
| 1 | 1 | 评论1 | 2017-05-17 00:00:00 | 2017-05-17 00:00:00 |
| 2 | 1 | 评论2 | 2017-05-17 00:00:01 | 2017-05-17 00:00:01 |
| 3 | 2 | 评论1 | 2017-05-17 00:00:02 | 2017-05-17 00:00:02 |
| 4 | 2 | 评论2 | 2017-05-17 00:00:03 | 2017-05-17 00:00:03 |
| 5 | 3 | 评论1 | 2017-05-17 00:00:04 | 2017-05-17 00:00:04 |
| 6 | 1 | 评论3 | 2017-05-17 00:00:05 | 2017-05-17 00:00:05 |
| 7 | 4 | 评论1 | 2017-05-17 00:00:06 | 2017-05-17 00:00:06 |
| 8 | 4 | 评论2 | 2017-05-17 00:00:07 | 2017-05-17 00:00:07 |
| 9 | 4 | 评论3 | 2017-05-17 00:00:08 | 2017-05-17 00:00:08 |
| 10 | 4 | 评论4 | 2017-05-17 00:00:09 | 2017-05-17 00:00:09 |
| 11 | 3 | 评论2 | 2017-05-17 00:00:10 | 2017-05-17 00:00:10 |
+----±--------±--------±--------------------±--------------------+

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

在comment表中,每个用户最后评论的内容就是id为6,4,11,10的记录。

使用group by查询

select * from comment group by user_id;
+----+---------+---------+---------------------+---------------------+
| id | user_id | content | addtime             | lastmodify          |
+----+---------+---------+---------------------+---------------------+
|  1 |       1 | 评论1   | 2017-05-17 00:00:00 | 2017-05-17 00:00:00 |
|  3 |       2 | 评论1   | 2017-05-17 00:00:02 | 2017-05-17 00:00:02 |
|  5 |       3 | 评论1   | 2017-05-17 00:00:04 | 2017-05-17 00:00:04 |
|  7 |       4 | 评论1   | 2017-05-17 00:00:06 | 2017-05-17 00:00:06 |
+----+---------+---------+---------------------+---------------------+
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以看到结果,分组后只会返回分组内的第一条数据。因为group by语法没有进行组内排序的功能,只会按mysql默认的排序显示。


如何才能对group by分组内的数据进行排序了,这个需要根据不同的需求处理。


1.id最大的,评论时间肯定最新

这种情况我们可以使用id代替时间去搜寻并组内排序,使用max(id)就可以获取到每个分组中最大的评论id(即最新的评论)

select * from comment where id in(select max(id) from comment group by user_id) order by user_id;
+----+---------+---------+---------------------+---------------------+
| id | user_id | content | addtime             | lastmodify          |
+----+---------+---------+---------------------+---------------------+
|  6 |       1 | 评论3   | 2017-05-17 00:00:05 | 2017-05-17 00:00:05 |
|  4 |       2 | 评论2   | 2017-05-17 00:00:03 | 2017-05-17 00:00:03 |
| 11 |       3 | 评论2   | 2017-05-17 00:00:10 | 2017-05-17 00:00:10 |
| 10 |       4 | 评论4   | 2017-05-17 00:00:09 | 2017-05-17 00:00:09 |
+----+---------+---------+---------------------+---------------------+
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9



2.id与评论时间没有关系,id大的评论时间可能不是最新

这种情况我们就需要使用max(addtime)来获取最新的评论,但因为不同用户的评论时间有可能相同,因此还需要加多user_id这个条件去查询。

重新创建测试数据

truncate table comment;

INSERT INTO comment (id, user_id, content, addtime, lastmodify) VALUES
(1, 1, ‘评论1’, ‘2017-05-17 00:00:00’, ‘2017-05-17 00:00:00’),
(2, 1, ‘评论2’, ‘2017-05-17 00:10:01’, ‘2017-05-17 00:10:01’),
(3, 2, ‘评论1’, ‘2017-05-17 00:10:02’, ‘2017-05-17 00:10:02’),
(4, 2, ‘评论2’, ‘2017-05-17 00:00:03’, ‘2017-05-17 00:00:03’),
(5, 3, ‘评论1’, ‘2017-05-17 00:10:04’, ‘2017-05-17 00:10:04’),
(6, 1, ‘评论3’, ‘2017-05-17 00:00:05’, ‘2017-05-17 00:00:05’),
(7, 4, ‘评论1’, ‘2017-05-17 00:00:06’, ‘2017-05-17 00:00:06’),
(8, 4, ‘评论2’, ‘2017-05-17 00:10:07’, ‘2017-05-17 00:10:07’),
(9, 4, ‘评论3’, ‘2017-05-17 00:00:08’, ‘2017-05-17 00:00:08’),
(10, 4, ‘评论4’, ‘2017-05-17 00:00:09’, ‘2017-05-17 00:00:09’),
(11, 3, ‘评论2’, ‘2017-05-17 00:00:10’, ‘2017-05-17 00:00:10’);

select * from comment;
+----±--------±--------±--------------------±--------------------+
| id | user_id | content | addtime | lastmodify |
+----±--------±--------±--------------------±--------------------+
| 1 | 1 | 评论1 | 2017-05-17 00:00:00 | 2017-05-17 00:00:00 |
| 2 | 1 | 评论2 | 2017-05-17 00:10:01 | 2017-05-17 00:10:01 |
| 3 | 2 | 评论1 | 2017-05-17 00:10:02 | 2017-05-17 00:10:02 |
| 4 | 2 | 评论2 | 2017-05-17 00:00:03 | 2017-05-17 00:00:03 |
| 5 | 3 | 评论1 | 2017-05-17 00:10:04 | 2017-05-17 00:10:04 |
| 6 | 1 | 评论3 | 2017-05-17 00:00:05 | 2017-05-17 00:00:05 |
| 7 | 4 | 评论1 | 2017-05-17 00:00:06 | 2017-05-17 00:00:06 |
| 8 | 4 | 评论2 | 2017-05-17 00:10:07 | 2017-05-17 00:10:07 |
| 9 | 4 | 评论3 | 2017-05-17 00:00:08 | 2017-05-17 00:00:08 |
| 10 | 4 | 评论4 | 2017-05-17 00:00:09 | 2017-05-17 00:00:09 |
| 11 | 3 | 评论2 | 2017-05-17 00:00:10 | 2017-05-17 00:00:10 |
+----±--------±--------±--------------------±--------------------+

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

符合条件的应该是id为2,3,5,8的记录

select a.* from comment as a right join 
(select user_id, max(addtime) as maxtime from comment where user_id is not null group by user_id) as b 
on a.user_id=b.user_id and a.addtime=b.maxtime order by a.user_id asc;

+------±--------±--------±--------------------±--------------------+
| id | user_id | content | addtime | lastmodify |
+------±--------±--------±--------------------±--------------------+
| 2 | 1 | 评论2 | 2017-05-17 00:10:01 | 2017-05-17 00:10:01 |
| 3 | 2 | 评论1 | 2017-05-17 00:10:02 | 2017-05-17 00:10:02 |
| 5 | 3 | 评论1 | 2017-05-17 00:10:04 | 2017-05-17 00:10:04 |
| 8 | 4 | 评论2 | 2017-05-17 00:10:07 | 2017-05-17 00:10:07 |
+------±--------±--------±--------------------±--------------------+

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

使用right join可以减少外层的数据集。
where user_id is not null 可以使group by user_id时使用索引。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL中,group by语法本身不提供组内排序的功能。然而,我们可以通过一些方法来实现组内排序。下面是两种常见的方法方法一:使用子查询和排序 可以使用子查询来先排好序,然后再使用group by进行分组。例如,我们可以在子查询中先按照指定的排序规则对数据进行排序,然后再使用group by对结果进行分组。具体的SQL语句如下所示: SELECT * FROM ( SELECT t1.*, t2.nick_name, t2.head_portrait FROM tb_circle_post t1, tb_user t2 WHERE t1.user_id = t2.id AND t1.is_delete = 1 ORDER BY t1.create_time DESC, t1.likes DESC LIMIT 0,50 ) temp GROUP BY user_id ORDER BY create_time DESC, likes DESC LIMIT 0,3 这个SQL语句首先在子查询中对数据进行排序,然后使用group by对user_id进行分组,最后再次按照指定的排序规则对结果进行排序。这样就可以实现组内排序的效果。 方法二:使用聚合函数和子查询 另一种方法是使用聚合函数和子查询来实现组内排序。具体的SQL语句如下所示: SELECT t1.user_id, MAX(t1.create_time) AS max_create_time FROM tb_circle_post t1 GROUP BY t1.user_id ORDER BY max_create_time DESC 在这个SQL语句中,我们使用MAX函数获取每个用户的最大创建时间,然后使用group by对user_id进行分组。最后,我们再按照最大创建时间进行降序排序,从而实现了组内排序。 需要注意的是,以上两种方法适用于不同的场景,具体应根据实际需求来选择合适的方法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值