关于MAX()函数的一点思考
本文同时发表在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()函数的一点思考的更多相关文章
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- [数据库]关于MAX()函数的一个坑
之前写了这么一条sql语句,目的是取出表中itemid最大的那一条数据. SELECT date, MAX(itemid) AS itemid, group FROM mytable GROUP BY ...
- MSSQL显错注入爆数字型数据的一点思考
Title:MSSQL显错注入爆数字型数据的一点思考 --2011-02-22 15:23 MSSQL+ASP 最近在弄个站点,密码是纯数字的,convert(int,())转换出来不报错,也不知道其 ...
- 对dump脱壳的一点思考
对dump脱壳的一点思考 偶然翻了一下手机日历,原来今天是夏至啊,时间过的真快.ISCC的比赛已经持续了2个多月了,我也跟着比赛的那些题目学了2个月.......虽然过程很辛苦,但感觉还是很幸运的,能 ...
- 关于KMP的一点思考
关于KMP的一点思考 KMP的\(next\)数组的性质很精妙,有必要开一个坑学习一下 Part 1 啥是next \(next[i]\)表示对于\(pre_i\)这个字符串,这个抠出来的字符串本身后 ...
- JS Math.max() 函数
Math.max(a,b,...,x,y) -- 返回数个数字中较大的值 max是maximum的缩写,中文"最大量"的意思 max函数语法Math.max(a,b,...,x,y ...
- Matlab:max函数
Matlab中max函数在矩阵中求函数大小的实例如下: C = max(A)返回一个数组各不同维中的最大元素.如果A是一个向量,max(A)返回A中的最大元素.如果A是一个矩阵,max(A)将A的每一 ...
- oracle max()函数和min()函数
当需要了解一列中的最大值时,可以使用MAX()函数:同样,当需要了解一列中的最小值时,可以使用MIN()函数.语法如下. SELECT MAX (column_name) / MIN ...
- C语言求两个函数中的较大者的MAX函数
//求两个函数中的较大者的MAX函数 #include <stdio.h> int main(int argc, const char * argv[]) { printf("i ...
随机推荐
- 75、django之ORM补充
本篇导航: QuerySet 中介模型 查询优化 一.QuerySet 1.可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. > ...
- 项目实战5—企业级缓存系统varnish应用与实战
企业级缓存系统varnish应用与实战 环境背景:随着公司业务快速发展,公司的电子商务平台已经聚集了很多的忠实粉丝,公司也拿到了投资,这时老板想通过一场类似双十一的活动,进行一场大的促销,届时会有非常 ...
- 将后面的m个数移到前面
#include<iostream> #include<algorithm> #include<stdio.h> #include<numeric> u ...
- TCP/IP 协议 ----- 协议栈
文章是作者对tcp/ip协议族的一些看法,借鉴TCP/IP详解卷一的内容,进行总结归纳,并阐述自己的一些看法. TCP/IP协议栈· : 整个协议栈被分为了四层,每一层协议负责不同的功能: 链路层:负 ...
- ##1.Centos7环境准备-- openstack pike
##1.Centos7环境准备 openstack pike 安装 目录汇总 http://www.cnblogs.com/elvi/p/7613861.html ##.Centos7环境准备 #Ce ...
- HAUT 1261地狱飞龙 自适应辛普森 数值积分
1261: 地狱飞龙 时间限制: 1 秒 内存限制: 64 MB 提交: 300 解决: 68 题目描述 最近clover迷上了皇室战争,他抽到了一种地狱飞龙,很开心.假设地域飞龙会对距离为d的敌 ...
- HttpClient(一)HttpClient抓取网页基本信息
一.HttpClient简介 HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程工具包, 并且它支 ...
- poj 1318Word Amalgamation
题目链接:http://poj.org/problem?id=1318 /*题意:在字母乱序的单词里面找到字母相同的字典里面的单词*/ /*此题的主要思路是要将字符排序,然后找对应,如果相同,那么就将 ...
- OpenXml读取word内容(二)
注意事项 上一篇已经说明,这次就不一一说了,直接来正文: word内容 相关代码 方法1 static void Main(string[] args) { string wordPathStr = ...
- Dos命令的巧用
豪华绚丽的Windows让人们把DOS抛到遥远的记忆角落,然而,真正有价值的东西不会轻易退出历史的舞台.很多人都已经习惯于 Windows的图形化用户界面,熟不知古老的DOS命令却可以轻易的办到很多事 ...