获取group by最后一条记录
create table login_log (id int primary key auto_increment, uid int, login_at datetime, login_device varchar(16))
INSERT INTO `login_log` (`id`, `uid`, `login_at`, `login_device`) VALUES (1, 1, '2022-04-01 14:34:54', 'PC'); INSERT INTO `login_log` (`id`, `uid`, `login_at`, `login_device`) VALUES (2, 2, '2022-03-01 14:35:08', 'MOBILE'); INSERT INTO `login_log` (`id`, `uid`, `login_at`, `login_device`) VALUES (3, 1, '2022-04-14 14:35:27', 'WEB'); INSERT INTO `login_log` (`id`, `uid`, `login_at`, `login_device`) VALUES (4, 2, '2022-04-30 14:35:35', 'WEB');
select * from login_log;
id uid login_at login_device 1 1 2022-04-01 14:34:54 PC 2 2 2022-03-01 14:35:08 MOBILE 3 1 2022-04-14 14:35:27 WEB 4 2 2022-04-30 14:35:35 WEB
group by后默认是获取第一条记录的,
如果只想获取group by后的某个字段的最大值,比如说要获取用户最后的登录时间,那么我们可以:
select uid, max(login_at) as last_login_at from login_log group by uid
uid last_login_at 1 2022-04-14 14:35:27 2 2022-04-30 14:35:35
但是,我们可能会有这样的需求:获取用户的最后登录时间以及登录设备
。
你可能会想到:
select uid, max(login_at) as last_login_at, login_device from login_log group by uid
这样是不行的,上面已经提及到group by后默认是会取第一条数据,所以这样查出来的login_device将会是分组后的第一条数据,即用户第一次登录时所使用的设备,而不是最后登录时间所对应的登录设备。
那么有以下几种
select * from login_log where id in (select max(id) from login_log group by uid)
or
select * from login_log as log1 join (select max(id) as id from login_log group by uid) as log2 where log1.id = log2.id
select log1.* from login_log as log1 left join login_log as log2 on log1.uid = log2.uid and log1.id < log2.id where log2.id is null
select * from login_log as log1 where not exists ( select * from login_log as log2 where log2.uid = log1.uid and log2.Id > log1.Id )
WITH ranked_log AS ( SELECT log.*, ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id DESC) AS rn FROM login_log AS log ) SELECT * FROM ranked_log WHERE rn = 1;
参考文档:StackOverflow