数据表结构和数据如下:

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. 构建于 B/S 端的 3D 摄像头可视化监控方案

    前言 随着视频监控联网系统的不断普及和发展, 网络摄像机更多的应用于监控系统中,尤其是高清时代的来临,更加快了网络摄像机的发展和应用. 在监控摄像机数量的不断庞大的同时,在监控系统中面临着严峻的现状问 ...

  2. 使用.NET Core创建Windows服务(二) - 使用Topshelf方式

    原文:Creating Windows Services In .NET Core – Part 2 – The "Topshelf" Way 作者:Dotnet Core Tut ...

  3. 初次接触python时,整理的一些基础操作

    1.window下python简单使用 (1).使用工具网址 https://jingyan.baidu.com/article/9f7e7ec0ec2e676f2915545f.html (2).各 ...

  4. onethinkphp 添加钩子报错

    今天改了下程序再保存,出现错误:Namespace declaration statement has to be the very first statement in the script 度娘一 ...

  5. SpringBoot2+Netty打造通俗简版RPC通信框架(升级版)

    背景         上篇文章我简单的介绍了自己打造的通俗简版RPC通信框架,这篇是对简版的增强~         如果大家对此项目还感兴趣的话,可到码云上瞄瞄:Netty-RPC         上 ...

  6. Windows10 1903错误0xc0000135解决方案

    Windows10 1903错误0xc0000135解决方案 === windows10 1903是2019年Mircosoft推出的最新版windows操作系统,但是有很多机器装上之后会存在不支持. ...

  7. Flutter中TabBarView切换状态保存

    TabBarView 类似于Android中的viewPager,但是默认是没有实现切换分页状态保存的.估计是出于节约内存的原因吧. 发现这个问题的时候,搜索了一下全网.大致就两种解决方案,1是修改源 ...

  8. SEER区块浏览器开发指南

    区块浏览器基本功能 区块链浏览器是浏览区块链信息的主要窗口,每一个区块所记载的内容都可以从区块链浏览器上进行查阅.用户可以使用区块链浏览器查询记录在区块中的交易信息,包括转账.预测.账户管理和社区治理 ...

  9. Java编程思想——第17章 容器深入研究 读书笔记(二)

    五.List的功能方法 排除Collection已包含的方法外还增加了 boolean addAll(int index, Collection<? extends E> c);从索引位置 ...

  10. Unix 线程共享创建进程打开的文件资源(1)

    执行环境:Linux ubuntu 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 ...