原文来自MySQL 5.7 官方手册:12.20.3 MySQL Handling of GROUP BY
SQL-92和更早版本不允许SELECT列表,HAVING条件或ORDER BY列表引用未在GROUP BY子句中命名的非聚合列的查询。即以下查询是被禁止的:
SELECT o.custid, c.name, MAX(o.payment)
FROM orders AS o, customers AS c
WHERE o.custid = c.custid
GROUP BY o.custid;
SQL-1999以及更高版本允许将这种查询作为一个可选项,前提是这些列在功能上依赖GROUP BY列(if they are functionally dependent on GROUP BY columns)——如果name和custid之间存在这种关系,则查询是合法的,例如custid是customer的一个主键。
MySQL 5.7.5及更高版本实现了对功能依赖的检测。如果启用了ONLY_FULL_GROUP_BY SQL模式(默认情况下是这样),MySQL会拒绝在Select列别、Having条件或者ORDER BY列表中有引用既未在GROUP BY子句中命名也未在功能上依赖于它们的非聚合列。
在5.7.5之前,MySQL不检测功能依赖性,默认情况下不启用ONLY_FULL_GROUP_BY。(难怪,我的是5.7.21,默认不开启。)
那当不启用ONLY_FULL_GROUP_BY时,MySQL就不得不接受前面这种查询。在这种情况下,服务器可以*选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的,这可能不是您想要的。
此外,添加ORDER BY子句不会影响每个组中值的选择。结果集的排序发生在值被选择之后,所以ORDER BY并不会影响服务器如何选择每个组中的值。
当你知道,由于数据的某些属性,每个未在GROUP BY中命名的非聚合列中的所有值对于每个组都是相同的。此时禁止ONLY_FULL_GROUP_BY可能是有用的。
以下的讨论展示功能性依赖、以及当功能性依赖缺失时MySQL产生的错误信息,以及让MySQL在功能性依赖缺失时接受查询的方式。
在ONLY_FULL_GROUP_BY模式下,下面的查询可能是非法的:
SELECT name, address, MAX(age) FROM t GROUP BY name;
但,如果name是t的一个主键,又或者name是一个unique、NOT NULL字段,这个查询会变成合法的。在这种情况下,MySQL会识别出查询列address功能性依赖与group列。例如,若name是一个主键,则其值确定address的值,因为每个组只有一个主键值,因此只有一行。因此,MySQL对组中address值的选择并不会有随机性,也不需要拒绝查询。
反过来,如果name是并不是t的一个主键,又或者name也不是一个unique、NOT NULL字段,这个查询就是非法的了,因为在这种情况下,MySQL不能推断出功能依赖性并发生错误:
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP
BY clause and contains nonaggregated column 'mydb.t.address' which
is not functionally dependent on columns in GROUP BY clause; this
is incompatible with sql_mode=only_full_group_by
那如果非要MySQL接受这个查询,就可以使用ANY_VALUE()函数:
SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;
当然,也可以放大招,禁止ONLY_FULL_GROUP_BY模式。
然而,这里的例子非常简单。 特别是,我们不太可能在单个主键列上进行分组,因为每个组只包含一行。其它对于在更复杂的查询中演示“功能性依赖”的示例,参考12.20.4。
如果一个select查询中包含了聚合函数,却没有GROUP BY子句。那么在ONLY_FULL_GROUP_BY模式下,它不能在select子句的列表中、HAVING条件中、ORDER BY列表中包含非聚合列。如下所示:
/*sql_mode=ONLY_FULL_GROUP_BY*/
mysql> SELECT name, MAX(age) FROM t;
ERROR 1140 (42000): In aggregated query without GROUP BY, expression
#1 of SELECT list contains nonaggregated column 'mydb.t.name'; this
is incompatible with sql_mode=only_full_group_by
不存在Group By子句时,就只存在一个组,同时也不确定为这个组选择哪个name值。这种情况下,如果MySQL选择的name值是无关紧要的,ANY_VALUE()就可以派上用场了:
/*不会报错*/
SELECT ANY_VALUE(name), MAX(age) FROM t;
在MySQL 5.7.5及更高版本中,ONLY_FULL_GROUP_BY也会影响使用了DISTINCT和ORDER BY的查询。
假设具有三列c1,c2和c3的表t,其中包含以下行:
/* c1 c2 c3
1 2 A
3 4 B
1 2 C */
假设我们执行以下查询,期望结果按c3列进行排序:
SELECT DISTINCT c1, c2 FROM t ORDER BY c3;
为了对结果排序,必须先删除重复项。但是要这样做,我们应该保留第一行还是第三行?这种任意选择会影响c3的保留值,而反过来c3的保留值又会影响排序,使得排序也任意了。
为了防止这个问题,如果任何ORDER BY表达式不满足以下条件中的至少一个,则有DISTINCT和ORDER BY的查询将被拒绝为无效:
- 表达式与select列表中的某个相等;
- 所有被该表达式引用、并且属于查询所选表的列,都是select列表中国的元素
MySQL相对于标准SQL的另一个扩展是:允许在Having子句中引用在SELECT从句中命名的别名。
例如,以下查询返回name值出现一次的行:
SELECT name, COUNT(name) FROM orders
GROUP BY name
HAVING COUNT(name) = 1;
但是MySQL扩展后可以如下使用:
SELECT name, COUNT(name) AS c FROM orders
GROUP BY name
HAVING c = 1;
NOTE:在MySQL 5.7.5之前,启用ONLY_FULL_GROUP_BY会禁用此扩展,因此需要使用非别名表达式来编写HAVING子句。
按前面的我的笔记,Having子句是在Select子句前被执行的,看起来似乎是错的?试验了一下,在我的版本(5.7.21)中,这样做没问题(猜想一下,和编译顺序相关?):
select SID,count(SId) as n from sc group by SId having n=3; /* +------+---+
| SID | n |
+------+---+
| 01 | 3 |
| 02 | 3 |
| 03 | 3 |
| 04 | 3 |
+------+---+ */
还可以提一下,标准SQL在GROUP BY子句中仅允许有列表达式(column expressions),因此诸如此类的语句无效,因为FLOOR(value / 100)是非列表达式( noncolumn expression):
SELECT id, FLOOR(value/100)
FROM tbl_name
GROUP BY id, FLOOR(value/100);
而MySQL对此进行了扩展,上述语句有效。
标准SQL也不允许GROUP BY子句中出现别名,MySQL则允许。所以上述查询也可以更改为:
SELECT id, FLOOR(value/100) AS val
FROM tbl_name
GROUP BY id, val;
这个val被视为列表达式。
当GROUP BY中出现非列表达式时,MySQL会识别该表达式与Select子句列表中的表达式之间的相等性。这意味着启用了ONLY_FULL_GROUP_BY SQL模式后,包含GROUP BY id,FLOOR(value/100)的查询是有效的,因为Select列表中出现了相同的FLOOR()表达式。
但是,MySQL不会尝试识别GROUP BY非列表达式的功能依赖(functional dependence),因此以下查询在启用ONLY_FULL_GROUP_BY时无效,即使Select列表中的第三个表达式是一个关于id列的简单公式:id与GROUP BY中的FLOOR()相加。(即id+FLOOR(value/100)与GROUP BY的列不存在功能依赖)
SELECT id, FLOOR(value/100), id+FLOOR(value/100)
FROM tbl_name
GROUP BY id, FLOOR(value/100);
解决方法是使用派生表:
SELECT id, F, id+F
FROM
(SELECT id, FLOOR(value/100) AS F
FROM tbl_name
GROUP BY id, FLOOR(value/100)) AS dt;
MySQL 聚合函数(三)MySQL对GROUP BY的处理的更多相关文章
-
MySQL 聚合函数(二)Group By的修饰符——ROLLUP
原文为MySQL 5.7 官方手册:12.20.2 GROUP BY Modifiers 一.ROLLUP 修饰符的意义 GROUP BY子句允许添加WITH ROLLUP修饰符,该修饰符可以对分组后 ...
-
MYSQL 行转列 以及基本的聚合函数count,与group by 以及distinct组合使用
在统计查询中,经常会用到count函数,这里是基础的 MYSQL 行转列 以及基本的聚合函数count,与group by 以及distinct组合使用 -- 创建表 CREATE TABLE `tb ...
-
第08章 MySQL聚合函数
第08章 MySQL聚合函数 我们上一章讲到了 SQL 单行函数.实际上 SQL 函数还有一类,叫做聚合(或聚集.分组)函数,它是对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值. 1 ...
-
MySQL聚合函数、控制流程函数(含navicat软件的介绍)
MySQL聚合函数.控制流程函数(含navicat软件的介绍) 一.navicat的引入:(第三方可视化的客户端,方便MySQL数据库的管理和维护) NavicatTM是一套快速.可靠并价格相宜的数据 ...
-
MySQL 聚合函数与count()函数
一.MySQL中的聚合函数 MySQL 5.7文档的章节:12.20.1 Aggregate (GROUP BY) Function “聚合/组合”函数(group (aggregate) funct ...
-
mysql聚合函数和分组
文章实例的数据表,来自上一篇博客<mysql简单查询>:http://blog.csdn.net/zuiwuyuan/article/details/39349611 一. 聚合函数 聚合 ...
-
MySQL数据库学习笔记(四)----MySQL聚合函数、控制流程函数(含navicat软件的介绍)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
-
Mysql 聚合函数返回NULL
[1]聚合函数返回NULL 当where条件不满足时,聚合函数sum().avg()的返回值为NULL. (1)源数据表 (2)如下SQL语句 SELECT sClass, COUNT(*) AS t ...
-
MySQL聚合函数、控制流程函数
[正文] 一.navicat的引入:(第三方可视化的客户端,方便MySQL数据库的管理和维护) NavicatTM是一套快速.可靠并价格相宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设 ...
随机推荐
-
Python之路,day8-Python基础
***面向对象的好处*** 更容易扩展.提高代码使用效率,使你的代码组织性更强,更清晰 更适合复杂项目的开发 封装 把功能的实现细节封装起来,只暴露调用接口 继承 多态 接口继承 定义 类----&g ...
-
PLL失锁
2016-07-05 现象:在低温(-30度以下)下,射频锁定信号出现周(大约20ms)期性高低电平的变化,由于MCU检测一次需要的时间很长(大于500ms), 大概总是检测不到失锁状态,所以不会出现 ...
-
我的Android第四章:Android的adb命令使用以及SQlite数据库运用
adb是什么?:adb的全称为Android Debug Bridge,就是起到调试桥的作用. adb有什么用?:借助adb工具,我们可以管理设备或手机模拟器的状态.还可以进行很多手机操作, ...
-
MAXIMO-IBM文件夹的笔记
MAXIMO--IBM整套文件的目录结构及常用的文件说明: applications文件装的maximo的最重要的文件,包括ear包等发布文件. 进入applications文件夹里,maximo文件 ...
-
NSURLSession使用实战教程
我的前面两篇文章介绍了NSURLSession套件的使用和NSURLSession套件的主要类.今天我们使用NSURLSession来完成一个小的应用程序.在实战之前,我先补充一点,为什么苹果会主推N ...
-
oracle的nvl函数的使用解析
Oracle的Nvl函数 nvl( ) 函数 从两个表达式返回一个非null 值. 语法 NVL(eExpression1, eExpression2) 参数 eExpression1, eExpre ...
-
Delphi——Window 消息 - 转载▼
Delphi是Borland公司的一种面向对象的可视化软件开发工具. Delphi集中了Visual C++和Visual Basic两者的优点:容易上手.功能强大,特别是在界面设计.数据库编程.网络 ...
-
onchar
void CMfcView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)//Windows响应函数 { // TODO: Add your messag ...
-
Javascript技巧实例精选(1)—鼠标选择动态改变网页背景颜色
>>点击这里下载html源文件代码<< 采用Javascript实现,用鼠标点击相应颜色,动态改变网页背景颜色 这是截图 相应的Javascript源代码为: var hex ...
-
jms的初步认识
(内容取自:http://itindex.net/detail/49721-jms-jms-%E5%BA%94%E7%94%A8) 什么是JMS? JMS即java消息服务, JMS通过消息的形式来降 ...