获取group by最后一条记录

获取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
  • exists的方式
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
)
  • window function的方式(mysql8)
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

你可能感兴趣的:(获取group by最后一条记录)