MySQL分组查询每组最新一条数据的三种实现方法
创作时间:
作者:
@小白创作中心
MySQL分组查询每组最新一条数据的三种实现方法
引用
1
来源
1.
https://www.zhangshengrong.com/p/zAaOp4VmNd/
在开发报表功能时,经常会遇到需要根据某个字段分组查询每组最新一条记录的需求。本文以一个实际案例为基础,详细介绍了在MySQL中实现这一需求的三种方法,并对每种方法的优缺点进行了分析。
前言
在开发报表功能时,经常会遇到需要根据某个字段分组查询每组最新一条记录的需求。本文以一个实际案例为基础,详细介绍了在MySQL中实现这一需求的三种方法,并对每种方法的优缺点进行了分析。
注意事项
- 数据库版本:MySQL 5.7+
- 执行 GROUP BY 语句时可能会遇到
sql_mode=only_full_group_by的问题,可以通过以下方式解决:
set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
准备SQL
为了便于演示,我们创建一个模拟的用户钱包明细表:
DROP TABLE IF EXISTS `customer_wallet_detail`;
CREATE TABLE `customer_wallet_detail` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`customer_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
`happen_amount` varchar(15) NULL DEFAULT '0' COMMENT '发生金额 带'-'号的代表扣款',
`balance_amount` varchar(15) NULL DEFAULT '0' COMMENT '可用余额',
`create_time` bigint(20) NULL DEFAULT NULL COMMENT '发生时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '用户钱包明细' ;
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (1, 1, '100', '100', 1670300656630);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (2, 1, '-10', '90', 1670300656640);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (3, 1, '5', '95', 1670300656650);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (4, 3, '998', '998', 1670300656660);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (5, 3, '-100', '898', 1670300656670);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (6, 3, '-98', '800', 1670300656680);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (7, 2, '666', '666', 1670300656690);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (8, 2, '-66', '600', 1670300656695);
INSERT INTO `test`.`customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `happen_time`) VALUES (9, 2, '-600', '0', 1670300656699);
错误查询
尝试使用子查询和 GROUP BY 查询最新一条数据时,发现查询结果总是最旧的一条数据:
SELECT
*
FROM
( SELECT * FROM customer_wallet_detail ORDER BY create_time DESC ) t1
GROUP BY
t1.customer_id;
错误原因
在MySQL 5.7及之后的版本中,如果 GROUP BY 的子查询中包含 ORDER BY,但 GROUP BY 不与 LIMIT 配合使用,ORDER BY 会被忽略掉。
方法一
通过添加 LIMIT 条件来实现功能:
SELECT
*
FROM
( SELECT * FROM customer_wallet_detail ORDER BY create_time DESC ) t1
GROUP BY
t1.customer_id
LIMIT 9;
方法二(适用于自增ID和创建时间排序一致)
使用 MAX() 函数来实现该功能:
SELECT
*
FROM
customer_wallet_detail
WHERE
id IN ( SELECT MAX( id ) FROM customer_wallet_detail GROUP BY customer_id )
ORDER BY
customer_id;
方法三(适用于自增ID和创建时间排序一致)
将 IN 查询替换为连接查询:
SELECT
t1.*
FROM
customer_wallet_detail t1
INNER JOIN ( SELECT MAX( id ) AS id FROM customer_wallet_detail GROUP BY customer_id ) t2 ON t1.id = t2.id
总结
结合业务测试结果,方法三是最合适的,SQL简单且性能适中。方法一虽然可行但实现较为复杂,方法二在大数据量下性能较差。最终选择哪个方案主要取决于具体业务场景。
MAX()函数和MIN()这一类函数和GROUP BY配合使用存在问题
MAX()函数和MIN()这一类函数和GROUP BY配合使用时,可能会导致查询结果不准确。正确的查询方式应该确保分组后的数据与聚合函数的结果对应一致。
正确查询:
错误查询:
热门推荐
打破限制性信念,显化无限丰盛
合金材料检测全维度解析:从成分到应用的精准把控
抑郁症患者挑战自我怎么办
有效缓解鼻子不通气的日常保健与应对方法总结
如何正确使用和维护变速箱?怎样避免对变速箱造成损坏?
寻味金华,一方火腿的传承与演绎
栗子的营养价值与食用禁忌:从功效到食用方法的全面解析
情侣游戏终极指南 2025超流行的情侣游戏合集
佳能打印机如何更换墨盒(简单步骤教您更换佳能打印机墨盒)
透视8000条分红承诺:三大趋势凸显 守信公司“钱”景可期
大白菜选购指南:黄色与绿色大白菜的区别及选购技巧
湖北盲派八字命理:揭秘其独特性与实践应用
唐玄宗与杨贵妃:一段承载爱情与权力的生死离别
初级经济师(人力资源管理方向)职业价值与备考策略全解析
从学生到元帅:毛主席和贺龙的传奇人生
睡觉鼻塞解决方案:为什么晚上睡觉容易鼻塞?儿童鼻塞怎么办?
AGA 与基因之间的关系
车驾管知识科普:机动车转籍(电子化转入)指南
最新宽带速率报告出炉,哪家网速最快
资源分配图算法:原理、步骤与应用场景详解
绿美郁南丨护林员龙醒华:守护山林42载 从未发生过一宗山火
有台灯需要开室内大灯吗?护眼台灯如何摆?关于护眼台灯知识解答
花椒种植技术全攻略:从选地到管理的详细指南
卡塔尔世界杯守门员精彩表现全面解析与战术探讨
徐州医科大学附属医院刘苏教授团队:术后麻醉恢复的理想体位新发现!
如何保护嗓子科学发声?“用、护、练”三字诀,教您练就一副好嗓音
中国传统木雕图案及其文化寓意详解(汇总)
属蛇的人是什么命?
襄阳牛油面:一座城市的味道传奇
澳大利亚家庭暴力保护法:为受害者撑起一片天