sql分组查询每组最新的一条数据

本文探讨了在MySQL中如何正确查询每个分组的最新记录,针对子查询排序无效的问题提出两种解决方案:一是对子查询结果进行LIMIT限制,二是利用MAX函数结合LEFT JOIN操作。这两种方法在效率上相差不大,需要根据实际业务需求和数据情况进行选择。
摘要由CSDN通过智能技术生成

原文地址:https://www.cnblogs.com/java-spring/p/11498457.html
开发中经常会遇到,分组查询最新数据的问题,比如下面这张表(查询每个地址最新的一条记录):

sql如下:

复制代码


– Table structure for test


DROP TABLE IF EXISTS test;
CREATE TABLE test (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
address varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
create_time timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;


– Records of test


INSERT INTO test VALUES (1, ‘张三1’, ‘北京’, ‘2019-09-10 11:22:23’);
INSERT INTO test VALUES (2, ‘张三2’, ‘北京’, ‘2019-09-10 12:22:23’);
INSERT INTO test VALUES (3, ‘张三3’, ‘北京’, ‘2019-09-05 12:22:23’);
INSERT INTO test VALUES (4, ‘张三4’, ‘北京’, ‘2019-09-06 12:22:23’);
INSERT INTO test VALUES (5, ‘李四1’, ‘上海’, ‘2019-09-06 12:22:23’);
INSERT INTO test VALUES (6, ‘李四2’, ‘上海’, ‘2019-09-07 12:22:23’);
INSERT INTO test VALUES (7, ‘李四3’, ‘上海’, ‘2019-09-11 12:22:23’);
INSERT INTO test VALUES (8, ‘李四4’, ‘上海’, ‘2019-09-12 12:22:23’);
INSERT INTO test VALUES (9, ‘王二1’, ‘广州’, ‘2019-09-03 12:22:23’);
INSERT INTO test VALUES (10, ‘王二2’, ‘广州’, ‘2019-09-04 12:22:23’);
INSERT INTO test VALUES (11, ‘王二3’, ‘广州’, ‘2019-09-05 12:22:23’);
复制代码
平常我们会进行按照时间倒叙排列然后进行分组,获取每个地址的最新记录,sql如下:

SELECT * FROM(SELECT * FROM test ORDER BY create_time DESC) a GROUP BY address
但是查询结果却不是我们想要的:

执行时间按倒叙排列结果为:

所以真正想要得到的结果是id为2/8/11的记录,上面的查询得到的却是1/5/9,这是为什么呢?

因为在mysql5.7的时候,子查询的排序已经变为无效了,可能是因为子查询大多数是作为一个结果给主查询使用,所以子查询不需要排序的原因。

那么我们应该怎么查呢,有两种方式:

第一种:

SELECT * FROM(SELECT * FROM test ORDER BY create_time DESC LIMIT 10000) a GROUP BY address
结果为:

对子查询的排序进行limit限制,此时子查询就不光是排序,所以此时排序会生效,但是限制条数却只能尽可能的设置大些

第二种:

SELECT t.* FROM (SELECT address,max(create_time) as create_time FROM test GROUP BY address) a LEFT JOIN test t ON t.address=a.address and t.create_time=a.create_time
通过MAX函数获取最新的时间和地址(因为需要按照地址分组),然后作为一张表和原来的数据进行联查,

条件就是地址和时间要和获取的最大时间和地址相等,此时结果为:

这两种方式的查询效率差不太多,第二种比第一种查询稍微快一点,可能是由于第二种方式的子查询只有两个字段(时间,被分组字段)的缘故吧!

感兴趣的可以照一张字段多的数据量大的表查询一下比较比较。

PS:第二种方式中最新的记录,不能同时地点和时间都相同,如果出现这种情况,第二种方式会查出把这两条记录都查出来,而第一条不会。

所以根据业务和数据情况来选择其中一种方式,毕竟效率差不太多。

劈天造陆,开辟属于自己的天地!!!与君共勉

可以通过Mybatis Plus的Lambda QueryWrapper和子询来实现分组后每组最新一条数据的功能。具体实现步骤如下: 1. 构建Lambda QueryWrapper对象,设置分组条件和排序条件: ``` QueryWrapper<Entity> wrapper = new QueryWrapper<>(); wrapper.select("group_id", "max(create_time) as create_time") .groupBy("group_id") .orderByDesc("create_time"); ``` 2. 构建子询,每组最新一条数据的id: ``` QueryWrapper<Entity> subWrapper = new QueryWrapper<>(); subWrapper.select("id") .inSql("concat(group_id, '_', create_time)", "select concat(group_id, '_', max(create_time)) from entity group by group_id"); ``` 3. 根据子询构建Lambda QueryWrapper对象,每组最新一条数据的详细信息: ``` QueryWrapper<Entity> queryWrapper = new QueryWrapper<>(); queryWrapper.in("id", subWrapper); List<Entity> entityList = entityMapper.selectList(queryWrapper); ``` 其中,第1步中的select语句中,group_id为分组字段,create_time为时间字段,max(create_time)表示获取每组最新一条数据的时间。orderByDesc("create_time")表示按时间倒序排列,确保每组最新一条数据排在最前面。 第2步中的子询中,concat(group_id, '_', create_time)表示将group_id和create_time拼接成一个字符串,以便后面使用inSql函数询。 第3步中的in函数中,将子询的结果作为参数传入,每组最新一条数据的详细信息。 这样就可以实现分组后每组最新一条数据的功能了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值