Mysql8的分组排序
Mysql8之前Group By支持分组排序
如:
select * from ( select * from user_position order by userId,time desc ) as u group by u.userId
或如:
select * from user_position group by userId desc
会取每组时间最新的一条,官方给出解释:
默认情况下GROUP BY隐式排序(即,缺少GROUP BY列的ASC或DESC指示符)。但是,不推荐依赖于隐式GROUP BY排序(即,在没有ASC或DESC指示符的情况下排序)或GROUP BY的显式排序(即,通过对GROUP BY列使用显式ASC或DESC指示符)。要生成给定的排序 ORDER,请提供ORDER BY子句。
但是在Mysql8之后不再支持这两种排序
具体原因:见 Removal of implicit and explicit sorting for GROUP BY
替代方式:
1、通过limit关键词,如:
select * from ( select * from user_position order by userId,time desc limit 9999 ) as u group by u.userId
使用limit之后,在group by 之前会保持排序
弊端:limit的数量有时候很难清楚
2、使用 in的方式
SELECT * FROM message_audit cma LEFT JOIN message cm ON cm.id = cma.message_id WHERE cma.id IN ( SELECT max( id ) FROM message_audit GROUP BY message_id )
弊端:in的id数量过大的话,效率极其低下,满足不了要求
3、使用窗口函数(分析函数) ROW_NUMBER() OVER()
在mysql8.0之后,开始支持窗口函数,我们可是使用窗口函数来完成分组排序,并且更加方便,如:
WITH tb AS (SELECT cm.msg_title, cma.message_id, cma.id, cma.create_time, cma.audit_status, cma.audit_reason, cma.audit_time, cma.external_audit_status, cma.external_audit_reason, ROW_NUMBER () OVER ( PARTITION BY cma.message_id ORDER BY cma.create_time DESC ) AS RN FROM message_audit cma LEFT JOIN message cm ON cm.id = cma.message_id WHERE cma.sys_audit_status = 1 ) SELECT * FROM tb WHERE RN = 1
解释: ROW_NUMBER () OVER ( PARTITION BY cma.message_id ORDER BY cma.create_time DESC ) AS RN,根据 message_id来分组,根据 create_time来排序
获取的结果标记行号RN,最好根据RN=1来获取最新的记录,当然我们也可以获取最新的两条、三条记录,处理结果比第二种方法效果更好