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配合使用时,可能会导致查询结果不准确。正确的查询方式应该确保分组后的数据与聚合函数的结果对应一致。
正确查询:
错误查询:
热门推荐
如何选择长期保险的购买策略?这些策略有哪些依据?
国产发动机技术哪家强?吉利仅排第三,第一众望所归
从《黑神话:悟空》看未来游戏趋势:高互动性、个性化与全球化
湖南省境内旅游景点推荐,湖南14个5A的旅游景点肯定不能错过
水溶性酚醛树脂的生产工艺
不同面料衣服的特征、保养和洗涤方法
绿色、智能、创新,雄安新区“未来之城”集聚发展新动能!
实用的合唱发声训练技巧
硬件基础知识全解析:深入理解计算机组件及其功能
水产养殖中碳源氮源的计算方法及添加量是多少?
铃兰花怎么养
摩托车报废的流程是什么?如何合法地处理报废摩托车?
吃过的人都说好!馄饨调馅和汤底的秘密大公开!
电视背景墙装修设计全攻略:从材料选择到风水布局
申请变更、追加被执行人要点汇总
祝融:中国神话中的火神与南海神
拿铁咖啡笔记:从历史沉淀到现代风潮的全面解析
蒙古族介绍:起源与文化特色
畜牧兽医专业就业前景如何?就业方向有哪些?
第三方存管的开通流程如何?这种开通流程对资金安全有何保障?
自动挡的自动驻车功能怎样使用?使用自动驻车时需规避哪些问题?
PE环境服务器维护与故障排查顺利入门指南
不领取失业金的后果和影响是什么?
Excel表格打开之后格式都没了怎么办
如何使用行程安排模板来优化您的旅行计划?
时间炼金术:普洱茶的古今传奇!
了解波伏瓦的最好方式,读她的自传
真正的git合并
21世纪亚洲最佳功夫动作电影Top20
水杯材质哪种好?一文详解不同材质水杯的安全使用指南