mysql 组内排序_mysql组内排序取最大值

最近业务反馈一个查询异常的问题,需要DBA对查询结果异常给出解释,并帮助他们解决该问题。问题本质是一个组内排序取最大值的问题,根据业务需求,我构建了测试用例

测试用例--建表

create table testorder

(id int not null,

no int not null,

name char(10) not null,

primary key(id)

)engine=innodb;

--写入数据

insert into testorder values (1,1,'Mike'),(2,2,'John'),(3,3,'wyett'),(4,4,'Herry'),(5,5,'Mike'),(6,1,'John'),(7,2,'John'),(8,1,'Mike'),(9,1,'Mike');

--查询1

select * from testorder;

+----+----+-------+

| id | no | name  |

+----+----+-------+

|  1 |  1 | Mike  |

|  2 |  2 | John  |

|  3 |  3 | wyett |

|  4 |  4 | Herry |

|  5 |  5 | Mike  |

|  6 |  1 | John  |

|  7 |  2 | John  |

|  8 |  1 | Mike  |

|  9 |  1 | Mike  |

+----+----+-------+

--查询2

select * from testorder order by no desc;

+----+----+-------+

| id | no | name  |

+----+----+-------+

|  5 |  5 | Mike  |

|  4 |  4 | Herry |

|  3 |  3 | wyett |

|  2 |  2 | John  |

|  7 |  2 | John  |

|  1 |  1 | Mike  |

|  6 |  1 | John  |

|  8 |  1 | Mike  |

|  9 |  1 | Mike  |

+----+----+-------+

--查询3select * from (select id,no,name from testorder order by no desc)a group by a.name;

查询3这条SQL是我们需要讨论的内容,也是业务线为实现组内排序取最大值所采用的SQL。标准的程序员反馈问题方式:XXX时间点之前查询时正常的,这之后突然就不正常了,你们DBA是不是做什么改动了?我把数据恢复到自己的测试机,返回值也是正常的。暂且不去管姿势是否正确,对这条SQL的分析,我们其实可以看出:(1)程序员期待group by执行结果是按照临时表a的数据顺序来取值;(2)程序员未考虑版本因素,数据量变化的因素;为此,我构建了上面的测试用例。

测试

在不同版本的MySQL来进行测试:发现在Percona 5.5,Percona 5.1,MySQL 5.6关闭sql_mode= ONLY_FULL_GROUP_BY,MySQL5.1等版本下,返回值确如程序员期待的顺序,按照order by no desc的顺序,相同name返回no值最大的数据;+----+----+-------+

| id | no | name  |

+----+----+-------+

|  4 |  4 | Herry |

|  2 |  2 | John  |

|  5 |  5 | Mike  |

|  3 |  3 | wyett |

+----+----+-------+

在mysql5.7,关闭sql_mode= ONLY_FULL_GROUP_BY和mariadb 10.*版本中,相同的name值,返回则是取了最早写入的数据行,忽略了order by no desc,按照数据的逻辑存储顺序来返回;+----+----+-------+

| id | no | name  |

+----+----+-------+

|  4 |  4 | Herry |

|  2 |  2 | John  |

|  1 |  1 | Mike  |

|  3 |  3 | wyett |

+----+----+-------+

其实在这里,SQL等价于select id,no,name from testorder group by name。这里我们看出不同版本的返回值是不同的,先搁置数据量的变化引起执行结果不同的讨论,因为数据量大小很难测试。

官方文档

对上面的测试结果,在官方文档上,有如下的参考If ONLY_FULL_GROUP_BY is disabled...In this case, the server is free to choose any value from each group,

so unless they are the same, the values chosen are indeterminate, which is probably not what you want.

Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause.

Result set sorting occurs after values have been chosen, and ORDER BY does not affect which value within

each group the server chooses.

ONLY_FULL_GROUP_BY这个SQL_MODE出在mysql5.6(mariadb 10.0)时被引入,但本文讨论的内容和它无关,具体可以自己查看文档,这里不做讨论。在5.6,5.5的官方文档有相同的内容,Mariadb也有类似的解释If you select a non-grouped column or a value computed from a non-grouped column, it is undefined

which row the returned value is taken from. This is not permitted if the ONLY_FULL_GROUP_BY SQL_MODE is used.

并且,对from后的subquery子表中的order by也给出了解释A query such as

SELECT field1, field2 FROM ( SELECT field1, field2 FROM table1 ORDER BY field2 ) alias

returns a result set that is not necessarily ordered by field2. This is not a bug.

A "table" (and subquery in the FROM clause too) is - according to the SQL standard - an unordered set of rows.

Rows in a table (or in a subquery in the FROM clause) do not come in any specific order.

好了,有了这些解释,问题很明朗:在from 后的subquery中的order by会被忽略

group by cloumn返回的行是无序的

因此,业务获得的正确的返回值也是误打误撞。

解决办法

那么这个问题该怎么解决?

在网上有一些SQL,很明显不满足需求,在这里做一下展示,希望同学们避免被误导:

错误SQL集合select id,sbustring(GROUP_CONCAT(distinct no order by no desc separator ''),'',1),name from testorder group by name;--通过添加索引来影响返回的结果集顺序

alter table testorder add index idx_no_name(no desc, name);

--结果证明即使如此,desc也不会被正确执行;--我司程序员的写法

select * from (select id,no,name from testorder order by no desc)a group by a.nameselect id,max(no),name from testorder group by name

我们可以这样写,虽然效率不高select a.id,a.no,a.name

from testorder a

inner join (select max(no) no,name

from testorder

group by name) b on a.no=b.no and a.name=b.name

group by name,no

或者这样select a.id,a.no,a.name

from testorder a

group by a.name,a.no

having a.no=(select max(no) from testorder where name=a.name)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/528718.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql索引抽密度_使用python脚本从abaqus输出数据库获取元素密度

属性关联如下:sectionAssignment将section连接到setset是{}的容器section将sectionAssignment连接到materialinstance连接到{}(可以来自另一个模型的部件)part连接到modelmodel连接到section如果可以,请使用.inp或.cae文件。下面的代码从一个打开的cae文…

python中plot和bar要求的格式不一样_在Python中matplotlib中匹配的图形大小,包括和不包含make_axes_locatable- divider colorbars...

我在22网格中有4个图形,但只希望右边的两个图形有条形(比例适用于行).我正在使用表格divider make_axes_locatable(ax)cax divider.append_axes("right", size"5%", pad0.05)plt.colorbar(im, caxcax)使颜色栏与这两个图的大小相匹配.然而,这使得两个带有…

禁用win10触摸屏手势_Win10平板边缘滑动手势大全及开启/关闭方法

Win10对于平板/触屏设备进行了特别优化,这体现在显示和操作等方面。对于操作方面,Windows10平板除了支持传统操作方法外,还有专门的边缘滑动手势。这些操作有别于之前的Win8/Win8.1,Win10边缘滑动操作共有以下四种形式&#xff1a…

java获取文件新增内容_关于java生成文件,立即又读这个文件但又找不到文件新增内容的问题...

展开全部写文件之后,应该有一个刷新流缓冲的flush()方法。该方法可以保证你可以读到你e69da5e6ba903231313335323631343130323136353331333332643238之前所写的内容。下面是我写的一个简单的测试用例:package test;import java.io.BufferedReader;import…

java的容器类有哪些实现方式_Java基础--容器类

面试官:Java的容器类你有什么了解吗?-:额,没有用过....面试官:你肯定用过,但你没有注意过....-:应该是吧....你知道什么是容器类吗?Java容器可以说是增强程序员编程能力的基本工具&a…

eclipse怎么导入java文件_eclipse怎么保存java文件?如何导入java文件?

eclipse开发工具很好用,是java开发人员的好帮手,但是一些新手java人员不知道eclipse怎么保存java文件?那么接下来,我们就来给大家讲解一下eclipse保存java文件的方法。Eclipse没有提供自动保存的功能,只能自己写脚本每隔多久保存…

asin java_Java asin() 方法

Java asin() 方法asin() 方法用于返回指定double类型参数的反正弦值。语法double asin(double d)参数d -- 任何原生数据类型。返回值返回指定double类型参数的反正弦值。实例public class Test{public static void main(String args[]){double degrees 45.0;double radians M…

java集合系列_Java集合系列01-Java集合概述

1.Java集合基本概念在编程中,常常需要集中存放多个数据。从传统意义上讲,数组是我们的一个很好的选择,前提是我们事先已经明确知道我们将要保存的对象的数量,因为数组长度在初始化时指定,意味着只能保存定长的数据。一…

java黄金连分数_蓝桥杯 | Java B组省赛真题练习——黄金连分数-Go语言中文社区...

标题: 黄金连分数黄金分割数0.61803... 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。 对于某些 精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加…

mysql 备份需要的权限_mysqldump 备份数据库用户所需要的权限

mysqldump 所需要的权限说明:1、对于table 来说mysqldump 最少要有select 权限。2、对于view 来说mysqldump 要有show view 权限。3、对于trrigger 来说mysqldump 要有trriger 权限。4、如果要产生一份一致的备份 mysqldump 要有lock tables 权限。mysql> create…

java赋值运算符_11.Java赋值运算符

赋值运算符 , , -, *, /, %运算符运算范例结果赋值a3,b2a3,b2加等于a3,b3;ab;a5,b2;-减等于a3,b2,a-b;a1,b2;*乘等于a3,b2,a*b;a6,b2/除等于a3,b2,a/b;a1,b2;%模等于a3,b2,a%b;a1,b2ab 可以想象成 aab;变量声明完了之后,可以使用赋值语句(assignment statement)给变…

php mysql 开发微博_php+mysql基于Android的手机微博应用开发

摘要:本系统采用Eclipse作为开发工具,数据库基于MySQL,服务器的编写使用的是PHP语言,开发了基于Android平台开的C/S模式的手机微博系统。系统从符合操作简便、界面友好、使用灵活、实用安全的要求出发,完成了用户的注册…

python 数组维度_python – 非常基本的Numpy数组维度可视化

NumPy中ndarray的解剖结构如下所示:(来源:Physics Dept, Cornell Uni)一旦离开2D空间并进入3D或更高维空间,行和列的概念就不再有意义了.但是你仍然可以直观地理解3D阵列.例如,考虑你的例子:In [41]: bOut[41]:array([[[ 1, 2, 3],[ 4, 5, 6]…

java通信项目_Java项目中的多线程通信如何利用Socket实现

Java项目中的多线程通信如何利用Socket实现发布时间:2020-11-24 16:44:40来源:亿速云阅读:96作者:Leah这期内容当中小编将会给大家带来有关Java项目中的多线程通信如何利用Socket实现,文章内容丰富且以专业的角度为大家…

Java捕获异常密码_Java捕获异常的问题

---恢复内容开始---在Java编译过程中,有时候会出现输入未按照规定输入的情况,此时需要警告用户输入错误,这就会是程序运行过程中出现异常。异常就是可预测但是又没办法消除的一种错误。所以在编写过程中,为了在程序当中不发生这样…

java判断输入月份_Java输入年份和月份判断多少天实例代码

前言本文主要介绍了如果通过输入年份月份输出天数的相关内容,下面话不多说了,来一起看看详细的介绍吧示例代码package com.ambow.www.ch03;import java.util.Scanner;public class Day {public static void main(String[] args) {Scanner sc new Scanne…

java基本要点_java代码的基本要点

java代码的基本要点Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。以下是小编为大家搜索整理的java代码的基本要点,希望能给大家带来帮助!更多精彩内容请及时关注我们应届毕业…

java脚本接口自动化测试_接口自动化测试实践的记录

接口测试实践的记录在敏捷开发交付的流程中,自动化测试实际上被放在一个看起来挺重要的位置,而自动化测试中,接口测试是一个投入产出比比较高的一种自动化测试的形式,而我自己也做了一个这样的脚手架一样的东西可以方便进行自动化…

java 安卓视频播放器_java - 学习做一个安卓视频播放器,有一些小问题!忘大家请教...

小葫芦2017-04-18 10:51:293楼首先解决你的一点疑惑,如何获取本地所有视频路径。Android系统在存储视频,音频,图片等资源的时候,会自动把其相关信息存储在数据库中,信息包括名字,大小,存储路径等…

java作业四_Java第四次作业

1.(二次方程式)为二次方程式ax2bxc0设计一个名为QuadraticEquation的类。这类包括:(1)代表三个系数的私有数据域a、b、c(2)一个参数为a、b和c的构造方法(3)a、b、c的三个get方法(4)一个名为getDiscriminant()的方法返回判别式,b2-4ac(5)一个名为getRoot1…