欢迎各位兄弟 发布技术文章
这里的技术是共享的
mysql的group by语法可以对数据进行分组,但是分组后的数据并不能进行组内排序。
例如一个评论表有多个用户评论,需要获取每个用户最后评论的内容。
创建测试数据表及数据
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 | 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 | + ----+---------+---------+---------------------+---------------------+ |
在comment表中,每个用户最后评论的内容就是id为6,4,11,10的记录。
使用group by查询
1 2 3 4 5 6 7 8 9 | 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 | + ----+---------+---------+---------------------+---------------------+ |
可以看到结果,分组后只会返回分组内的第一条数据。因为group by语法没有进行组内排序的功能,只会按mysql默认的排序显示。
如何才能对group by分组内的数据进行排序了,这个需要根据不同的需求处理。
1.id最大的,评论时间肯定最新
这种情况我们可以使用id代替时间去搜寻并组内排序,使用max(id)就可以获取到每个分组中最大的评论id(即最新的评论)
1 2 3 4 5 6 7 8 9 | 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 | + ----+---------+---------+---------------------+---------------------+ |
2.id与评论时间没有关系,id大的评论时间可能不是最新
这种情况我们就需要使用max(addtime)来获取最新的评论,但因为不同用户的评论时间有可能相同,因此还需要加多user_id这个条件去查询。
重新创建测试数据
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 | 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 | + ----+---------+---------+---------------------+---------------------+ |
符合条件的应该是id为2,3,5,8的记录
1 2 3 4 5 6 7 8 9 10 11 12 | 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 | + ------+---------+---------+---------------------+---------------------+ |
使用right join可以减少外层的数据集。
where user_id is not null 可以使group by user_id时使用索引。
来自 https://www.2cto.com/database/201705/639679.html