本文同时发表在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. Grafana+Prometheus系统监控之SpringBoot

    前言 前一段时间使用SpringBoot创建了一个webhook项目,由于近期项目中也使用了不少SpringBoot相关的项目,趁着周末,配置一下使用prometheus监控微服务Springboot ...

  2. 异常:Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException

    这个异常是出现在注入配置文件中配置好的属性时报错的: Injection of autowired dependencies failed; nested exception is java.lang ...

  3. QuickTime视频解析问题

    在QuickTime中可以解析出视频并播放视频,解析的格式后缀名为.mov,之后将该视频导入到Unity Project中,显示未解析到视频文件,本来应该会自动生成MovieTexture材质,但是并 ...

  4. 如何清除PHP中不需要的Layout模板

    最简单的办法就是在需要清除的静态页的最前端加上   {__NOLAYOUT__}  就可以清除所有的layout效果, 继而设置自己的css.js效果.

  5. ubuntu实时显示网速cpu占用和内存占用率

    ubuntu实时显示网速cpu占用和内存占用率 大家在使用ubuntu的时候,有没有想让它实时显示网速,内存占用率,或者cpu占用率呢?现在我就教大家怎么实现,就像下面这样 1. 添加indicato ...

  6. 实战-Mysql主从复制

    前言: Mysql内建的复制功能是构建大型高性能应用程序的基础.由于目前mysql的高可用性架构MMM和MHA均建立在复制的基础之上,本文就mysql主从复制进行实战描述,希望对读者提供帮助.之前 服 ...

  7. node.js入门必知

    目录: 一.node.js简介 1.1特点 1.2适合开发什么 1.3Node.js无法挑战老牌后台语言 二.http模块 一.node.js简介 Node.js开发服务器,数据.路由.本地关心的效果 ...

  8. linux个人情况总结

    linux主文件夹打不开 killall Nautilus linux下codeblocks编译文件权限不够,将文件建立在用户的目录下

  9. idea快速搭建springboot项目

    Spring Boot是由Pivotal团队提供的全新框架,设计目的是用来简化新Spring应用的初始搭建以及开发过程.它主要推崇的是'消灭配置',实现零配置. 那么,如何在idea中创建一个spri ...

  10. 【回文】leetcode - Shortest Palindrome

    题目: Shortest Palindrome Given a string S, you are allowed to convert it to a palindrome by adding ch ...