数据表结构和数据如下:

CREATE TABLE `commun_message_chat_single` (
`id` int() NOT NULL AUTO_INCREMENT,
`chat_id` int() DEFAULT '' COMMENT '会话id',
`from_id` varchar() DEFAULT NULL COMMENT '发送者 用户id',
`to_id` varchar() DEFAULT NULL COMMENT '接收者 用户id',
`content` text COMMENT '消息内容',
`type` tinyint() DEFAULT '' COMMENT '消息类型 1:文字 2:图片 3:文件',
`send_time` datetime DEFAULT NULL COMMENT '消息发送时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='单聊 聊天记录'; -- 插入数据的sql
INSERT INTO `commun_message_chat_single` VALUES (, , '', 'md_1', '', , '2019-10-16 08:25:50');
INSERT INTO `commun_message_chat_single` VALUES (, , '', 'md_1', '', , '2019-10-28 08:25:59');
INSERT INTO `commun_message_chat_single` VALUES (, , '', 'md_2', '', , '2019-10-01 08:26:21');
INSERT INTO `commun_message_chat_single` VALUES (, , '', 'md_2', '哈哈哈', , '2019-10-27 08:26:34');
INSERT INTO `commun_message_chat_single` VALUES (, , '', 'md_2', '测试测试', , '2019-10-10 08:28:27');

目前数据表所有数据如下:

mysql> select * from commun_message_chat_single where from_id = '11';
+----+---------+---------+-------+--------------+------+---------------------+
| id | chat_id | from_id | to_id | content | type | send_time |
+----+---------+---------+-------+--------------+------+---------------------+
| 60 | 10 | 11 | md_1 | 123 | 1 | 2019-10-16 08:25:50 |
| 61 | 10 | 11 | md_1 | 456 | 1 | 2019-10-28 08:25:59 |
| 62 | 10 | 11 | md_2 | 789 | 1 | 2019-10-01 08:26:21 |
| 63 | 10 | 11 | md_2 | 哈哈哈 | 1 | 2019-10-27 08:26:34 |
| 64 | 10 | 11 | md_2 | 测试测试 | 1 | 2019-10-10 08:28:27 |
+----+---------+---------+-------+--------------+------+---------------------+
5 rows in set (0.00 sec)

需求:查询from_id为11的数据 并且 和 每一个to_id 按照时间排序显示最新的一条数据(也就是显示:to_id是md_1的,按照时间排序id为61的符合结果;to_id是md_2的,按照时间排序id为63的符合结果)

符合该需求的2条数据如下:

+----+---------+---------+-------+-----------+------+---------------------+
| id | chat_id | from_id | to_id | content | type | send_time |
+----+---------+---------+-------+-----------+------+---------------------+
| 61 | 10 | 11 | md_1 | 456 | 1 | 2019-10-28 08:25:59 |
| 63 | 10 | 11 | md_2 | 哈哈哈 | 1 | 2019-10-27 08:26:34 |
+----+---------+---------+-------+-----------+------+---------------------+

实现该需求的sql语句如下(利用sql中的子查询):

SELECT * FROM (SELECT * FROM commun_message_chat_single WHERE from_id = '11' ORDER BY send_time DESC ) as
temp_table GROUP BY temp_table.to_id; -- 大概解释下该条sql语句:括号内的子查询是查询from_id为11的数据并且按照send_time从高到低排序,这里的子查询的结果会生成一个临时表,临时表这里取名为temp_table,然后外部查询将temp_table的结果进行分组。

mysql5.7版本以下执行结果如下(只在5.5和5.6版本试过):

+----+---------+---------+-------+-----------+------+---------------------+
| id | chat_id | from_id | to_id | content | type | send_time |
+----+---------+---------+-------+-----------+------+---------------------+
| 61 | 10 | 11 | md_1 | 456 | 1 | 2019-10-28 08:25:59 |
| 63 | 10 | 11 | md_2 | 哈哈哈 | 1 | 2019-10-27 08:26:34 |
+----+---------+---------+-------+-----------+------+---------------------+
2 rows in set (0.00 sec)

 mysql5.7版本执行结果如下:

+----+---------+---------+-------+---------+------+---------------------+
| id | chat_id | from_id | to_id | content | type | send_time |
+----+---------+---------+-------+---------+------+---------------------+
| | | | md_1 | | | -- :: |
| | | | md_2 | | | -- :: |
+----+---------+---------+-------+---------+------+---------------------+
rows in set (0.00 sec)

what?为啥5.7以下的版本是我们想要的结果,而5.7版本的执行结果居然不是我们期待的结果!高版本居然执行的结果不正确。。

为什么mysql5.7和5.7以下的版本会有不同的结果呢?

可以分别查看一下这条sql语句在两个不同版本数据库的sql执行计划:

mysql 5.7.21:

mysql5.5.62和5.6.44:

对比可以发现5.7版本的mysql在执行这条sql语句的时候缺少了一个derived的操作,通过查阅相关资料了解到mysql5.7对子查询进行了优化,认为子查询中的order by可以进行忽略,只要Derived table里不包含如下条件就可以进行优化:

①、UNION clause

②、GROUP BY

③、DISTINCT

④、Aggregation

⑤、LIMIT or OFFSET

看到了吧,如果要在mysql5.7中实现先排序后分组,这里可以加个limit,不过你的limit要足够大

mysql5.7解决办法如下:

SELECT * FROM (SELECT * FROM commun_message_chat_single WHERE from_id = '' ORDER BY send_time DESC LIMIT
) as temp_table GROUP BY temp_table.to_id;

mysql8.0及以上版本没试过,不过应该和5.7是一样的效果,都进行了优化。

PS:子查询不是mysql独有的,sqlserver等数据库也可以使用子查询

sql中实现先排序后分组的更多相关文章

  1. MySql下实现先排序后分组

    最近在工作中遇到一个先排序后分组的需求,发现MySql不同的版本有不同的结果,特此记录. 举例:要求在shop表中查询出各类型商店中价格最高的商品. --表结构-- create table `sho ...

  2. Java基础知识强化之IO流笔记52:IO流练习之 把一个文件中的字符串排序后再写入另一个文件案例

    1. 把一个文件中的字符串排序后再写入另一个文件 已知s.txt文件中有这样的一个字符串:"hcexfgijkamdnoqrzstuvwybpl" 请编写程序读取数据内容,把数据排 ...

  3. SQL中条件放在on后与where后的区别

    SQL中on条件与where条件的区别 数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和where条件的区别如下: ...

  4. SQL中前置0和后置0的处理问题

    在sql语句中经常遇到处理前置和后置数据的问题 1.首先使用convert转化函数对预处理的数据进行转化,CONVERT()函数可以将制定的数据类型转换为另一种数据类型 MySQL 的CAST()和C ...

  5. sql中的group by 和 having 用法解析

    转载博客:http://www.cnblogs.com/wang-123/archive/2012/01/05/2312676.html --sql中的group by 用法解析:-- Group B ...

  6. sql中group by 和having 用法解析

    --sql中的group by 用法解析:-- Group By语句从英文的字面意义上理解就是“根据(by)一定的规则进行分组(Group)”.--它的作用是通过一定的规则将一个数据集划分成若干个小的 ...

  7. mysql 怎样先排序再分组

    权游游牧族:众所周知!一句SqL语句不能先排序再分组.所以这里给出几个案例 --表结构-- create table `shop` ( `id` int (10) PRIMARY KEY, `shop ...

  8. 在oracle中,group by后将字符拼接,以及自定义排序

    1.在oracle中,group by后将字符拼接.任务:在学生表中,有studentid和subject两个字段.要求对studentid进行group by分组,并将所选科目拼接在一起.oracl ...

  9. mssql sqlserver 使用sql脚本获取群组后,按时间排序(asc)第一条数据的方法分享

    摘要: 下文讲述使用sql脚本,获取群组后记录的第一条数据业务场景说明: 学校教务处要求统计: 每次作业,最早提交的学生名单下文通过举例的方式,记录此次脚本编写方法,方便以后备查,如下所示: 实现思路 ...

随机推荐

  1. 体验StartOS

    旧电脑,原来使用的是win xp.随着win及其支持打软件打“成长”,电脑运行越来越慢了.一个操作需要很长的时间等待,终于,失去了耐心,换了新的电脑. 旧电脑弃置多年,留之无用,弃之可惜.偶发奇想,换 ...

  2. 更该clover软件图标(任务栏显示)

    1.首先介绍一个Clover软件,Clover 的功能就是给资源管理器加上 Chrome 一样的标签页,像下面这样,你会爱上它的效率,和浏览器一样的操作方式. 2.它自带的系统图标比较丑(虽然作者说挺 ...

  3. MongoDB 学习笔记之 匹配完整数组

    匹配完整数组: 创建一个集合(包含数组) db.ArrayTest.insert({name: "Sky" , address: [{"street" : &q ...

  4. 小程序webview调用微信扫一扫的“曲折”思路

    自上一篇遇到webview中没有返回按钮之后,虽然跳出坑了.解决方案:<小程序webview跳转页面后没有返回按钮完美解决方案> 但是,小程序踩坑之路并没有结束.在公众号网页中通过配置AP ...

  5. Redis面试篇 -- Redis主从复制原理

        Redis一般是用来支撑读高并发的,为了分担读压力,Redis支持主从复制.架构是主从架构,一主多从, 主负责写,并且将数据复制到其它的 slave 节点,从节点负责读. 所有的读请求全部走从 ...

  6. wsgi相关的

    目录 web 本质 http协议 请求方式 响应状态码 请求与响应文本格式 目录 web 本质   本质就是浏览器和服务器进行通信, http协议   也叫超文本传输协议(英文:HyperText T ...

  7. LeetCode_933-Number of Recent Calls

    求最近3000毫秒内有多少次调用请求,每一次ping的时间一定比上一次的时间高:解法可以判断最后面一个数t1与最前一个数t2的差不大于3000毫秒,如果大于就直接舍弃,t1与t2之间的个数就是请求次数 ...

  8. vodevs3031 最富有的人

    在你的面前有n堆金子,你只能取走其中的两堆,且总价值为这两堆金子的xor值,你想成为最富有的人,你就要有所选择. 输入描述 Input Description 第一行包含两个正整数n,表示有n堆金子. ...

  9. 2-SAT问题学习笔记+例题[洛谷P4792]

    一个不错的2-SAT文章:传送门 问题初入 什么是2-SAT SAT是适定性(Satisfiability)问题的简称 .一般形式为k-适定性问题,简称 k-SAT. 首先,把「2」和「SAT」拆开. ...

  10. 实验吧之【拐弯抹角】(url伪静态)

    题目地址:http://ctf5.shiyanbar.com/indirection/ 打开后给了源码 <?php // code by SEC@USTC echo '<html>& ...