mysql通过group by分组取最大时间对应的数据,提供两种有效方法。

本文讨论了在SQL查询中如何正确地获取每个项目中最大上项目时间对应的数据。错误代码展示了一个常见问题,即GROUP BY操作会返回每个分组中主键ID最小的记录。解决方案包括两种方法:一种是通过内连接实现,另一种利用SUBSTRING_INDEX函数。这两种方法都能够正确地获取每个项目最大上项目时间的数据,并确保ID匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、项目记录表project_record的结构和数据如下:

以下为项目记录表project_record的所有数据。project_id为项目Id,on_project_time为上项目时间。(每一条数据代表着上某个项目(project_id)的时间(on_project_time)记录)

2、我们的需求是:取出每个项目中最大上项目时间对应的那条数据。(即根据project_id分组,取出每组中最大的on_project_time对应的数据。)上方红框是我们要查出的数据

3、错误代码:

SELECT * 
FROM (SELECT * FROM project_record order by on_project_time desc) t 
GROUP BY project_id;

查询结果错误:

结果看似正确的,实则是错误的。每个项目最大的上项目时间能正确查出,但是数据对应的id不正确。

分析发现,对于每一个分组,分组后的结果总是取组中主键(id)最小的数据,即group by project_id 总会对project_id执行排序(正序)

 而不论临时表(t)中是否已排序,都会取组中主键id最小的一行数据。换句话说 临时表t 内的排序 无法影响外层的group by 的操作。

4、 正确方法如下:

方法一:

SELECT t1.*
FROM project_record t1
INNER JOIN (
SELECT DISTINCT(id) id
FROM project_record 
ORDER BY on_project_time DESC) AS t2 ON t2.id = t1.id
GROUP BY t1.project_id;

查询结果正确:

思路:需要关联一张表,这个关联表t2中的数据是对原表t1按照上项目时间倒叙排列,注意,此处必须使用distinct,此处distinct的作用可以理解为将t1表数据顺序固定为t2表顺序
主表GROUP BY 后会取出按条件分组后的第一条数据。

补充:关联t2表,如果有查询条件,需要将所有查询条件都写在关联的t2表中,如果写在主表的where中排序就失效了。后来发现的~

 

方法二:

select t1.*
FROM project_record t1
INNER JOIN (SELECT SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY on_project_time DESC),',',1) AS id
FROM project_record GROUP BY project_id) AS t2 ON t2.id = t1.id;

查询结果正确:

SUBSTRING_INDEX 用法:取排序后的分组的第一条数据。 

本人习惯使用第一种方法。

MySQL 中,当你使用 `GROUP BY` 对数据进行分组时,默认情况下只能选择那些用于分组的字段或经过聚合函数处理后的字段。这是因为 `GROUP BY` 创建的是每组的结果摘要行,而原始表格中的每一行信息都会被压缩成这一个汇总行。 但是有时候我们还想获分组字段的具体值。在这种情境下有两种常见解决办法: ### 方法一:利用聚合函数 你可以应用各种各样的聚合函数如 MAX(), MIN() 等等来提特定条件下非分组列的信息。例如: 假设有一个名为 orders 表格存储着订单详情: ```sql +----+----------+---------+ | ID | Customer | Price | +----+----------+---------+ | 1 | Alice | 100 | | 2 | Bob | 200 | | 3 | Alice | 150 | | 4 | Charlie | 300 | +----+----------+---------+ ``` 如果我们想得到每位客户的最高消费额以及对应的订单ID,就可以这么做: ```sql SELECT Customer, MAX(Price) as Max_Price, SUBSTRING_INDEX(GROUP_CONCAT(ID ORDER BY Price DESC), ',', 1) AS Order_ID_for_Max_Price FROM orders GROUP BY Customer; ``` 这里用到了两个技巧 - `MAX()` 找出最大价格;然后结合 `GROUP_CONCAT` 和字符串操作找到关联的最大价格所对应的第一个(如果有多个同样高的消费)Order ID. ### 方法二:采用窗口函数(Window Functions) 从 MySQL 8.0 开始引入了标准SQL里的窗口函数特性(Window Function),允许我们在不分组的情况下计算跨多行或多列的结果集的同时保持原有行列不变,这对于想要得非分组列很有帮助: 继续沿用上面例子, 如果现在需要知道每个客户他们各自所有的订单里最贵的那个的价格及那个具体的id号码, 我们可以这样写: ```sql WITH RankedOrders AS ( SELECT *, RANK() OVER(PARTITION BY Customer ORDER BY Price DESC) rank_num FROM orders ) SELECT * FROM RankedOrders WHERE rank_num = 1 ; ``` 在这个CTE(Common Table Expression)表达式内部先按照顾客分区(partition by customer),接着依据price降序排列(order by price desc),赋予相应排名(rank())。 最终选出排名第一的纪录就是我们要找的目标——即各个用户的最高花费连同其确切order id。 --- 以上就是在MYSQL中运用 GROUP BY 后如何有效非聚集栏位的基本策略啦!
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值