sql获取group by最后一条记录

这篇博客探讨了如何在SQL中获取GROUP BY操作后每个分组的最后一条记录,尤其是在处理用户最后登录时间这样的场景。文章通过创建测试表、插入数据并查看数据来展示问题,然后提供了四种解决方案:子查询、连表查询、EXISTS子句以及MySQL 8的窗口函数方法。
部署运行你感兴趣的模型镜像

获取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

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>首先,用户的问题是:“我想了解SQLGROUP BY是否只保留一条记录?” 这是一个直接的疑问句。 从用户的指令中,我有系统级规则: - 所有行内数学表达式必须用$...$格式,但这里的问题是关于SQL的,所以可能不需要数学表达式。我会注意在需要时使用。 - 独立公式用$$...$$,但SQL代码不是公式,所以我应该正常处理。 - 使用中文回答。 - 生成相关问题。 - 在引用段落末尾添加引用标识。 用户提供了几个引用: - 引用[1]:关于SQL LEFT JOIN后用GROUP BY去重。 - 引用[2]:关于删除重复记录并只保留一条。 - 引用[3]:关于sql获取group by最后一条记录。 - 引用[4]:关于GROUP BY最新一条记录。 这些引用是关于SQL中的GROUP BY和去重的。用户的核心问题是:GROUP BY是否只保留一条记录? 关键点是: - GROUP BY本身用于分组数据。 - 当使用GROUP BY时,它会将数据分组,每组返回一行。 - 在分组后,如果没有聚合函数,它会返回每组的第一条记录决于数据库实现)。 - 但在标准SQL中,SELECT列表中的非聚合列必须在GROUP BY子句中指定,否则行为未定义。 回答结构: 1. 直接回答用户问题。 2. 解释GROUP BY的工作原理。 3. 使用引用中的信息来支持。 4. 澄清误解。 5. 生成相关问题。 逐步回答: - 是的,GROUP BY通常用于分组数据,并返回每组一条记录。但这决于如何使用。 - 它会将相同的值分组,并为每个组返回一行。 - 在引用中: - [1]提到LEFT JOIN后用GROUP BY去重。 - [3]和[4]讨论如何获取每组的最新一条记录。 - [2]是关于删除重复记录。 - GROUP BY默认返回每组的第一条记录(在MySQL中),但可以通过ORDER BY和子查询来指定哪条记录。 精确回答: - GROUP BY本身不保证保留特定的记录;它分组后,可以使用聚合函数(如MAX, MIN)来选择值。 - 在MySQL中,如果没有ORDER BY,它会返回每组的第一条记录。 - 用户引用[4]展示了如何最新记录。 生成相关问题: - 基于主题,如: 1. GROUP BY如何工作? 2. 如何保留每组的最新记录? 3. GROUP BY和DISTINCT有什么区别? 4. 如何删除重复记录? 5. GROUP BY的性能影响? 确保回答真实可靠: - 基于SQL知识:GROUP BY用于分组,返回每组的汇总行。 - 它不是自动保留一条;它决于查询写法。 最终回答结构: 1. 介绍GROUP BY的功能。 2. 解释是否只保留一条记录。 3. 举例说明。 4. 引用相关段落。 5. 列出相关问题。 </think>### SQLGROUP BY是否只保留一条记录? 在SQL中,GROUP BY子句的核心功能是将数据按照指定列分组,并为每个分组返回一条汇总记录。但它**不会自动保留原始表中的特定一条记录**(如最新或最小ID的记录),而是结合聚合函数(如COUNT、MAX、MIN)计算值后生成一行结果。默认行为决于数据库实现和查询写法: - **分组后返回一行**:使用GROUP BY时,SQL会将所有具有相同分组键(GROUP BY列)的行合并为一个组,最终输出每组一条记录。例如,引用[3]提到,GROUP BY后默认每组的第一条记录(在MySQL中)[^3]。 - **不保留具体哪条记录**:GROUP BY本身不指定保留哪条原始记录。如果你需要保留每组中的特定记录(如最大ID或最新时间),必须通过子查询、ORDER BY或窗口函数来实现。引用[4]展示了如何结合MAX函数和子查询来最新记录[^4]。 - **与去重的区别**:GROUP BY常用于去重(如引用[1]中通过GROUP BY去重),但它不是简单的“保留一条记录”。DISTINCT关键字也能去重,但GROUP BY更灵活,支持聚合计算[^1]。 #### 示例说明 假设有一个订单表 `orders`: | order_id | customer_id | amount | order_date | |----------|-------------|--------|------------| | 1 | 101 | 100 | 2023-01-01 | | 2 | 101 | 150 | 2023-01-02 | | 3 | 102 | 200 | 2023-01-01 | - **基本GROUP BY查询(返回每组一条记录)**: ```sql SELECT customer_id, SUM(amount) AS total_amount FROM orders GROUP BY customer_id; ``` 输出: | customer_id | total_amount | |-------------|--------------| | 101 | 250 | | 102 | 200 | 这里,GROUP BY按`customer_id`分组,每组返回一行(聚合了所有amount)。 - **如何保留每组最新记录(需额外操作)**: 如引用[4]所示,需结合子查询和MAX函数[^4]: ```sql SELECT o.order_id, o.customer_id, o.amount, o.order_date FROM orders o WHERE o.order_date = ( SELECT MAX(order_date) FROM orders WHERE customer_id = o.customer_id ); ``` 这会返回每组(按customer_id)的最新订单记录。 #### 关键结论 - **GROUP BY默认返回每组一行记录**,但它是汇总行(包含聚合值),而非原始表中的具体某一行。 - 要保留特定记录(如最小ID或最新日期),必须添加逻辑,如引用[2]中删除重复记录时结合MIN函数[^2]或引用[4]的MAX方法[^4]。 - 在MySQL数据库中,未指定时可能组内第一条记录,但这不可靠;应显式使用ORDER BY和LIMIT来控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值