`

(转)MySQL 5.7默认ONLY_FULL_GROUP_BY语义介绍

 
阅读更多
http://www.ywnds.com/?p=8184
ONLY_FULL_GROUP_BY是MySQL提供的一个sql_mode,通过这个sql_mode来提供SQL语句GROUP BY合法性的检查,在MySQL的sql_mode是非ONLY_FULL_GROUP_BY语义时。一条select语句,MySQL允许target list中输出的表达式是除聚集函数或group by column以外的表达式,这个表达式的值可能在经过group by操作后变成undefined,例如:


mysql> create database test charset utf8mb4;
mysql> use test;
mysql> create table tt(id int,count int);
mysql> insert into tt values(1,1),(1,2),(2,3),(2,4);
mysql> select * from tt group by id;
+------+-------+
| id   | count |
+------+-------+
|    1 |     1 |
|    2 |     3 |
+------+-------+
2 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
mysql> create database test charset utf8mb4;
mysql> use test;
mysql> create table tt(id int,count int);
mysql> insert into tt values(1,1),(1,2),(2,3),(2,4);
mysql> select * from tt group by id;
+------+-------+
| id   | count |
+------+-------+
|    1 |     1 |
|    2 |     3 |
+------+-------+
2 rows in set (0.00 sec)
而对于语义限制都比较严谨的多家数据库,如SQLServer、Oracle、PostgreSql都不支持select target list中出现语义不明确的列,这样的语句在这些数据库中是会被报错的,所以从MySQL 5.7版本开始修正了这个语义,就是我们所说的ONLY_FULL_GROUP_BY语义,例如查看MySQL 5.7默认的sql_mode如下:


mysql> select @@global.sql_mode;
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
1
2
mysql> select @@global.sql_mode;
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
去掉ONLY_FULL_GROUP_BY模式,如下操作:


mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
1
mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
我们把刚才的查询再次执行:


mysql> select id,count from tt group by id;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.count' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
1
2
3
mysql> select id,count from tt group by id;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.count' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
刚才通过的查询语句被server拒绝掉了!

所以ONLY_FULL_GROUP_BY的语义就是确定select target list中的所有列的值都是明确语义,简单的说来,在ONLY_FULL_GROUP_BY模式下,target list中的值要么是来自于聚集函数的结果,要么是来自于group by list中的表达式的值。但是由于表达式的表现形式非常丰富,对于程序来说,很难精确的确定一些表达式的输出结果是明确的,比如:


mysql> select count from tt group by id+count,id;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.count' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
1
2
3
mysql> select count from tt group by id+count,id;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.count' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
在上面的查询语句中,其实count的值也是能被唯一确定的,但是由于程序无法分析出这种复杂的关系,所以这条查询也被拒绝掉了。

我们来看下哪些语句是在mysql的ONLY_FULL_GROUP_BY模式下是被支持的。


mysql> select id+1 from tt group by id+1;
+------+
| id+1 |
+------+
|    2 |
|    3 |
+------+
2 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
mysql> select id+1 from tt group by id+1;
+------+
| id+1 |
+------+
|    2 |
|    3 |
+------+
2 rows in set (0.00 sec)
这条语句target list中的id+1和group by中的id+1是严格匹配的,所以mysql认为target list中的id+1是语义明确的,因此该语句可以通过。

但下面这条就无法通过了。


mysql> select id+1 from tt group by 1+id;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.id' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
1
2
3
mysql> select id+1 from tt group by 1+id;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.id' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
因此,如果查询语句中的target list, having condition 或者order by list里引用了的表达式不是聚集函数,但是和group by list中的表达式严格匹配,该语句也是合法的(id+1和id+1是严格匹配的,id+1和id+2在mysql认为是不严格匹配的, id+1和1+id也是不严格匹配的)。


mysql> select id,max(count) from tt group by count;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.id' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
1
2
3
mysql> select id,max(count) from tt group by count;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tt.id' which is
not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
这条query被server拒绝掉了,因为target list中的id没有出现在聚集函数中,并且也没有出现在group by list中。

看下面这条语句:


mysql> select id+1 as a from tt group by a order by id+1;
+------+
| a    |
+------+
|    2 |
|    3 |
+------+
2 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
mysql> select id+1 as a from tt group by a order by id+1;
+------+
| a    |
+------+
|    2 |
|    3 |
+------+
2 rows in set (0.00 sec)
mysql允许target list中对于非聚集函数的alias column被group by、having condition以及order by语句引用(version 5.7中允许having condition引用alias column,version 5.6不支持having condition引用alias column),从上面两条语句可以看出,group by和order by中引用了alias column,并且其等价于基础列语义。


mysql> select id+count from tt group by id,count;
+----------+
| id+count |
+----------+
|        2 |
|        3 |
|        5 |
|        6 |
+----------+
4 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
mysql> select id+count from tt group by id,count;
+----------+
| id+count |
+----------+
|        2 |
|        3 |
|        5 |
|        6 |
+----------+
4 rows in set (0.00 sec)
从上面的语句可以看出,mysql的ONLY_FULL_GROUP_BY模式支持对basic column进行组合但是不支持对于复杂表达式进行组合,这个受限于表达式分析程度。

总结一下:

MySQL对于ONLY_FULL_GROUP_BY语义的判断规则是,如果group by list中的表达式是basic column,那么target list中允许出现表达式是group by list中basic column或者alias column的组合结果,如果group by list中的表达式是复杂表达式(非basic column或者alias column),那么要求target list中的表达式必须能够严格和group by list中的表达式进行匹配,否者这条查询会被认为不合法。
分享到:
评论

相关推荐

    银河麒麟amd64 MYSQL离线安装包 mysql5.7_kylin_amd64.zip

    本离线安装包“mysql5.7_kylin_amd64.zip”是针对银河麒麟AMD64平台定制的MySQL 5.7数据库服务器的安装文件,确保在该平台上能够顺利安装和运行MySQL。 MySQL 5.7是MySQL数据库的一个重要版本,它包含了多项改进...

    银河麒麟 armhf 架构 MYSQL离线安装包 mysql5.7_kylin_armhf.zip

    离线安装包mysql5.7_kylin_armhf.zip则专门针对银河麒麟armhf平台进行了优化,确保在该平台上能够顺畅运行。 离线安装包的优点在于用户无需连接互联网即可进行安装,这对于网络环境不稳定或者有严格安全要求的场合...

    银河麒麟_飞腾_MYSQL 离线安装包 mysql5.7_kylin_arm64.zip

    "mysql5.7_kylin_arm64.zip" 是针对银河麒麟和飞腾架构定制的MySQL 5.7版本的离线安装包。MySQL 5.7是社区版的一个稳定版本,提供了许多性能优化和新特性,包括InnoDB存储引擎的增强、查询优化器改进以及JSON支持等...

    mysql5.7 修改max_allowed_packet方法

    通过本文,我们详细介绍了如何在MySQL 5.7中查看和调整`max_allowed_packet` 参数。这对于处理大数据量的应用场景尤为重要。通过使用图形化管理工具,可以更加方便快捷地完成这一设置。需要注意的是,在调整参数时应...

    银河麒麟_龙芯_MYSQL离线安装包 mysql5.7_kylin_mips64el.zip

    这个“银河麒麟_龙芯_MYSQL离线安装包 mysql5.7_kylin_mips64el.zip”文件是专为银河麒麟操作系统在龙芯处理器平台上搭建MySQL 5.7数据库环境而准备的。离线安装包意味着用户可以在没有网络连接的情况下进行MySQL的...

    银河麒麟兆芯MYSQL离线安装包mysql5.7_kylin_i386.zip

    在这样的背景下,"银河麒麟兆芯MYSQL离线安装包mysql5.7_kylin_i386.zip" 是一个专为银河麒麟操作系统和兆芯处理器设计的MySQL 5.7数据库的离线安装包。这个包确保了在没有网络连接的情况下,用户也能在银河麒麟系统...

    MySQL5.7中的sql_mode默认值带来的坑及解决方法

    案例一:ONLY_FULL_GROUP_BY 问题描述 MySQL版本从5.6升级至5.7之后,部分SQL执行报错,报错信息如下: ERROR 1055 (42000): Expression #3 of XXXXXX list is not in GROUP BY clause and contain

    mysql5.7.31_windows_64.zip

    "mysql5.7.31_windows_64.zip" 文件是一个包含 MySQL 5.7.31 for Windows 64-bit 的压缩包,其核心组件是 "mysql5.7.31_windows_64.msi",这是一个基于 Microsoft Installer(MSI)的安装程序,提供可视化的图形安装...

    Mysql5.7及以上版本 ONLY_FULL_GROUP_BY报错的解决方法

    MySQL 5.7及以上版本引入了一个新的SQL标准模式`ONLY_FULL_GROUP_BY`,该模式旨在增强SQL查询的严格性,确保结果集的合法性。在早期的MySQL版本中,某些GROUP BY查询可以返回不确定的行数据,这在严格模式下是不允许...

    mysql5.7默认配置文件

    mysql5.7默认配置文件

    mysql5.7_bin_install.sh

    mysql5.7 二进制安装一键安装脚本 for centos 需要用bash运行 /bin/bash mysql5.7_bin_install.sh 安装过程中需要外网访问下载mysql程序文件

    mysql5.7_for_linux源码安装.pdf

    此外,`/etc/***f`配置文件中可以设置`sql_mode`,例如设置`ONLY_FULL_GROUP_BY`可以使得某些查询操作不受到限制。 最后,将MySQL的bin目录添加到系统的PATH环境变量中,确保MySQL命令行工具可以全局访问。 ```...

    mysql5.7.33_社区版.zip

    - 安装 MySQL 5.7.33 时,用户需下载适用于 Windows 10 的安装包,即 "mysql5.7.33_社区版.zip",解压后按照向导进行安装。 - 配置过程中,需要设定服务器类型(开发机器、生产服务器等)、安装路径、服务名以及...

    MySql版本问题sql_mode=only_full_group_by的完美解决方案

    在MySQL 5.7及更高版本中,默认启用`ONLY_FULL_GROUP_BY`,这会导致一些在旧版本中可能运行正常的查询在新版本中报错。这是因为这些查询在没有明确指定分组依据的情况下使用了非聚合函数,这在SQL标准中是不允许的。...

    mysql5.7.33_64位

    1. **系统兼容性**:确保你的 Windows 10 操作系统是 64 位的,因为这是与 mysql5.7.33_64 位版本相匹配的。32 位系统无法运行这个软件包。 2. **安装步骤**:安装过程可以通过访问提供的链接...

    mysql5.7_to_80_upgrade.zip

    MySQL是世界上最受欢迎的关系型数据库管理系统之一,从MySQL 5.7升级到8.0是一个重要的里程碑,因为每个新版本都带来了性能提升、功能增强和安全性的改进。在进行升级时,需要注意一系列的关键事项以确保过程顺利且...

    解决MySQL 5.7.9版本sql_mode=only_full_group_by问题

    在MySQL 5.7.9版本中,引入了一个新的默认SQL模式`ONLY_FULL_GROUP_BY`,这个模式旨在增强SQL查询的严谨性和一致性,遵循SQL标准。然而,它也可能导致一些原本在旧版本中能正常运行的查询出现错误。本文将详细讲解`...

    mysql5.7 审计插件及安装步骤

    MySQL 5.7 是一个广泛使用的开源关系型数据库管理系统,其审计插件是实现数据库活动监控和记录的重要工具。审计插件允许管理员跟踪并记录数据库的各种操作,如查询、登录尝试、权限更改等,这对于合规性、安全性和...

Global site tag (gtag.js) - Google Analytics