本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/103

考虑如下表和sql:

CREATE TABLE `iknow_team_info` (
`teamId` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`userNum` int(11) unsigned NOT NULL DEFAULT '0'',
PRIMARY KEY (`teamId`),
) ENGINE=InnoDB DEFAULT CHARSET=gbk' mysql> select teamId,userNum from iknow_team_info limit 10;
+--------+---------+
| teamId | userNum |
+--------+---------+
| 1 | 73 |
| 4 | 100 |
| 8 | 112 |
| 9 | 136 |
| 10 | 58 |
| 12 | 84 |
| 16 | 141 |
| 17 | 560 |
| 18 | 114 |
| 19 | 8 |
+--------+---------+
10 rows in set (0.01 sec) mysql> select teamId,max(userNum) from iknow_team_info;
+--------+--------------+
| teamId | max(userNum) |
+--------+--------------+
| 1 | 1000 |
+--------+--------------+
1 row in set (0.02 sec)

关于最后一个sql:查找人数(userNum)最多的行对应的teamId,为什么会返回1呢?很显然人数最多的行对应的teamId不是1。

在这里userNum列没有索引,mysql肯定会全表扫描:

mysql> explain select teamId,max(userNum) from iknow_team_info;
+----+-------------+-----------------+------+---------------+------+---------+------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+------+---------+------+-------+-------+
| 1 | SIMPLE | iknow_team_info | ALL | NULL | NULL | NULL | NULL | 12191 | |
+----+-------------+-----------------+------+---------------+------+---------+------+-------+-------+
1 row in set (0.00 sec)

我猜测的sql执行过程是这样的: 全表扫描,扫描的过程中记录下扫描过得最大的userNum以及对应的teamId,最后将结果返回。这个过程应该很清晰明了,为什么mysql没有返回正确结果呢?

最后在官方手册中寻找到了答案:

原来MAX()也是聚集函数的一种,所有聚集函数如下表:

当我们使用了上面表中的聚集函数但是却没有包含group by时,mysql会默认在所有满足条件的行上做聚集。

If you use a group function in a statement containing no GROUP BY clause, it is equivalent to grouping on all rows.

所以我们可以大胆的假设上面的sql等同于:

mysql> select teamId,max(userNum) from iknow_team_info group by null;
+--------+--------------+
| teamId | max(userNum) |
+--------+--------------+
| 1 | 1000 |
+--------+--------------+
1 row in set (0.02 sec)

mysql跟标准sql的一点不同是:mysql接受出现在select列表中但是没有出现在group by列表中的列。所以,当teamId不在group by的列表中时,mysql会在每一个分组中随机挑选出一个teamId,所以最后出现的teamId是1,不是正确的。

If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard SQL use of GROUP BY permits the select list, HAVING condition, or ORDER BY list to refer to nonaggregated columns even if the columns are not functionally dependent on GROUP BY columns. This causes MySQL to accept the preceding query. 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.

要想出现正确的结果,我们可以按照下面的方式书写sql:

mysql> select teamId,userNum from iknow_team_info order by userNum desc limit 1;
+--------+---------+
| teamId | userNum |
+--------+---------+
| 88010 | 1000 |
+--------+---------+
1 row in set (0.01 sec)

或者我们可以让teamId出现在group by的列表中,从而取出正确的teamId(即列出每个teamId组内的max(userNum)),再对所有的max(userNum)进行排序。

mysql> select teamId,max(userNum) maxNum from iknow_team_info group by teamId order by maxNum desc limit 1;
+--------+--------+
| teamId | maxNum |
+--------+--------+
| 88041 | 1000 |
+--------+--------+
1 row in set (0.02 sec)

参考资料:

How does SQL MAX() works?

Aggregate (GROUP BY) Function Descriptions

关于MAX()函数的一点思考的更多相关文章

  1. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

  2. [数据库]关于MAX()函数的一个坑

    之前写了这么一条sql语句,目的是取出表中itemid最大的那一条数据. SELECT date, MAX(itemid) AS itemid, group FROM mytable GROUP BY ...

  3. MSSQL显错注入爆数字型数据的一点思考

    Title:MSSQL显错注入爆数字型数据的一点思考 --2011-02-22 15:23 MSSQL+ASP 最近在弄个站点,密码是纯数字的,convert(int,())转换出来不报错,也不知道其 ...

  4. 对dump脱壳的一点思考

    对dump脱壳的一点思考 偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能 ...

  5. 关于KMP的一点思考

    关于KMP的一点思考 KMP的\(next\)数组的性质很精妙,有必要开一个坑学习一下 Part 1 啥是next \(next[i]\)表示对于\(pre_i\)这个字符串,这个抠出来的字符串本身后 ...

  6. JS Math.max() 函数

    Math.max(a,b,...,x,y) -- 返回数个数字中较大的值 max是maximum的缩写,中文"最大量"的意思 max函数语法Math.max(a,b,...,x,y ...

  7. Matlab:max函数

    Matlab中max函数在矩阵中求函数大小的实例如下: C = max(A)返回一个数组各不同维中的最大元素.如果A是一个向量,max(A)返回A中的最大元素.如果A是一个矩阵,max(A)将A的每一 ...

  8. oracle max()函数和min()函数

    当需要了解一列中的最大值时,可以使用MAX()函数:同样,当需要了解一列中的最小值时,可以使用MIN()函数.语法如下. SELECT          MAX (column_name) / MIN ...

  9. C语言求两个函数中的较大者的MAX函数

    //求两个函数中的较大者的MAX函数 #include <stdio.h> int main(int argc, const char * argv[]) { printf("i ...

随机推荐

  1. 使用vue2.x+webpack+vuex+sass+axios+elementUI等快速搭建前端项目框架

    一.本文将分享如何快速搭起基于webpack+vue的前端项目框架,利用vue的自己的脚手架工具vue-cli搭建起基本的环境配置,再通过npm包管理工具引入相应的依赖来完善项目的各种依赖框架.下面是 ...

  2. android TransFormexecption 解决

    近期编译的时候遇到这个问题.... > com.android.build.api.transform.Transformexception: java.util.zip.ZipExceptio ...

  3. ndk-stack使用方法

    最近在mac上编译android 版本,各种崩溃让人蛋疼,网上学习了下ndk-stack使用方法. 自己备忘下: 1.运行终端. 跳转到你android sdk 目录 因为你的adb 在里面. 如 c ...

  4. MySQL的安装(比较详细的安装步骤,包括客户端和服务端的安装,还有环境变量的配置以及使用Windows service启动MySQL)

    1.MySQL官网下载操作系统对应的MySQL安装包,解压之后就可以直接使用(免安装). MySQL安装包,一种是MySQL Enterprise Edition (commercial)企业版,还有 ...

  5. RFID电动车管理,智慧城市物联网建设的入口

    原谷歌CEO施密特说:"我可以非常直接地说,互联网将消失." 互联网在20多年来帮助人们解决了信息共享.交互,几乎在瞬间颠覆了很多传统的商业模式,把卖产品变为卖内容和服务,是个了不 ...

  6. 初识AOP与动态代理

    AOP AOP是指在jvm运行时, 动态将代码切入到指定位置. OOP是一个维度上写代码, AOP是把他切开来, 变成立体的. 这样的好处是: 业务逻辑跟辅助逻辑分离, 例如日志打印, 性能监控, 安 ...

  7. node.js之第一天

    一.http模块 //require表示引包,引包就是引用自己的一个特殊功能 var http = require("http"); //创建服务器,参数是一个回调函数,表示如果有 ...

  8. Android Toolbar 标题居中及字体样式自定义

    首先找到 toolbar 所在xml布局文件,将toolbar控件放置在一个相对布局(RelativeLayout)中,然后设置toolbar的title为空(随便打几个空格即可): 然后在 tool ...

  9. Jarvis OJ- [XMAN]level2/3_x64-Writeup——64位简单栈溢出

    两道64位栈溢出,思路和之前的32位溢出基本一致,所以放在一起 在这两道中体现的32位和64位的主要区别在于函数参数传递的方式 在32位程序运行中,函数参数直接压入栈中 调用函数时栈的结构为:调用函数 ...

  10. 互联网协议(Internet Protocol Suite)

    互联网实现分层:有的7层有的4层:阮一峰认为分五层(个人喜欢): 最底下的一层叫做"实体层"(Physical Layer),最上面的一层叫做"应用层"(App ...