本文同时发表在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. 为Spark Application指定不同的JDK版本

    随着企业内部业务系统越来越多,基于JVM的服务,通常情况线上环境可能会有多套JDK跑不同的服务.大家都知道基于高版本的Java规范编写的服务跑在低版本的JVM上会出现:java.lang.Unsupp ...

  2. web兼容性测试相关知识

    一.客户端兼容性 1.浏览器的兼容性测试 a.内核角度 Tridnt内核:代表作IE.腾讯.遨游.世界之窗等 Gecko内核:代表作Firefox webkit内核:代表作Safari.Chrome ...

  3. Spring MVC 学习总结(九)——Spring MVC实现RESTful与JSON(Spring MVC为前端提供服务)

    很多时候前端都需要调用后台服务实现交互功能,常见的数据交换格式多是JSON或XML,这里主要讲解Spring MVC为前端提供JSON格式的数据并实现与前台交互.RESTful则是一种软件架构风格.设 ...

  4. npm install 时报错 Unexpected end of input at 1:15930

    从github上clone代码后npm install,结果解决办法: npm config set registry https://registry.npm.taobao.org之后出现自动生成了 ...

  5. poj 2456 Aggressive cows && nyoj 疯牛 最大化最小值 二分

    poj 2456 Aggressive cows && nyoj 疯牛 最大化最小值 二分 题目链接: nyoj : http://acm.nyist.net/JudgeOnline/ ...

  6. 使用vee-validate表单插件是如何设置中文提示?

    最近在写vue表单验证的时候,在网上找到一款不错的插件vee-validate,在使用的过程中发现配置不了中文提示,这就很苦恼了,基本上网上的配置办法我都看过,都是有问题的,比如这种 import z ...

  7. 在Notepad++中添加运行快捷键

    在Notepad++中有运行的快捷键,想着如果编辑完Python文件能直接运行就好了,于是尝试了一下. 我安装的是win8.1,安装的notepad++将运行快捷键的文件shortcuts.xml,放 ...

  8. ssm开发使用redis作为缓存,使用步骤

    1.关于spring配置文件中对于redis的配置 <!-- redis配置 --> <bean id="jedisPoolConfig" class=" ...

  9. 如何配置 Health Check?- 每天5分钟玩转 Docker 容器技术(107)

    容器状态是 UP 的,应用就是健康的吗? 还真不一定!Docker 只能从容器启动进程的返回代码判断其状态,而对于容器内部应用的运行情况基本没有了解. 执行 docker run 命令时,通常会根据 ...

  10. 【算法】二叉查找树实现字典API

    参考资料 <算法(java)>                           — — Robert Sedgewick, Kevin Wayne <数据结构>       ...