sql獲取group by最後一條記錄
阿新 • • 發佈:2022-04-04
獲取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