Mysql ONLY_FULL_GROUP_BY模式详解、group by非查询字段报错

文章目录
  • 一、问题报错
  • 二、ONLY_FULL_GROUP_BY模式
    • 2.1、什么是ONLY_FULL_GROUP_BY?
    • 2.2、为什么要使用ONLY_FULL_GROUP_BY?
    • 2.3、查看sql_mode
  • 三、解决方法
    • 3.1、关闭only_full_group_by模式
      • 3.1.1、方法一:关闭当前会话中的only_full_group_by
      • 3.1.2、方法二:永久关闭only_full_group_by模式
    • 3.2、使用ANY_VALUE()函数
  • 四、其他
    • 4.1、无权限报错
    • 4.2、select后面的字段必须在group by后面出现?当group by遇上唯一索引或主键

以下内容基于Mysql8.0进行讲解ONLY_FULL_GROUP_BY模式。

一、问题报错

Mysql5.7版本以上对group by 分组有了新需求,要求group by 后的字段要与select后查询的字段一致,否则就会报错,报错信息如下:

[2024-09-29 10:48:54] [42000][1055] Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘test.tbl_test.name’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

测试用例如下:

create table tbl_test( id int primary key auto_increment, name varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci unique not null, age int comment '年龄', address varchar(50) comment '住址', update_time datetime default null ) comment '测试表'; insert into tbl_test(name,age,address,update_time) values ('zhangsan',25,'杭州',now()), ('李四',21,'武汉',now()), ('王五',25,'杭州',now());


对上述数据同时查询name与age字段,并根据age字段group by 后报错如下:

原因分析:MySQL5.7版本及以上默认设置了 mysql sql_mode =only_full_group_by属性,导致报错。

其中ONLY_FULL_GROUP_BY就是造成这个错误的罪魁祸首了,在这种严格模式下,对于group by聚合操作,若在select中的列没有在group by中出现,那么这个SQL就是不合法的。因为开发写的sql中,select列不在group by从句中,在使用group by时就会报错。

接下来我们一起看一下这个模式的原理以及这种情况如何解决。

二、ONLY_FULL_GROUP_BY模式

2.1、什么是ONLY_FULL_GROUP_BY?

ONLY_FULL_GROUP_BY是MySQL的一个SQL模式(SQL_MODE)之一,它要求在使用GROUP BY语句时,SELECT列表、HAVING条件或ORDER BY列表中的每个列,要么是聚合函数的一部分(如COUNT(),SUM(),AVG()等),要么必须在GROUP BY子句中明确指定。

这一模式的设计初衷是增强查询的准确性和可预测性,避免因为列的不明确引用而导致的数据错误或不一致。

2.2、为什么要使用ONLY_FULL_GROUP_BY?

  • 数据准确性:确保聚合查询的结果符合预期,防止因为非聚合列的不确定行为而导致的数据误导。
  • 一致性:在不同的数据库系统或配置间保持查询行为的一致性,减少迁移或升级时的兼容性问题。
  • 避免歧义:清晰定义查询的意图,减少因查询理解错误而导致的错误。

2.3、查看sql_mode

SELECT @@sql_mode; 或者 select @@GLOBAL.sql_mode;

查询出来的值为:

ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

以下为sql_mode常用值的含义,参考:

ONLY_FULL_GROUP_BY:对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中 NO_AUTO_VALUE_ON_ZERO:该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户希望插入的值为0,而该列又是自增长的,那么这个选项就有用了。 STRICT_TRANS_TABLES:在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制 NO_ZERO_IN_DATE:在严格模式下,不允许日期和月份为零 NO_ZERO_DATE:设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。 ERROR_FOR_DIVISION_BY_ZERO:在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如果未给出该模式,那么数据被零除时MySQL返回NULL NO_AUTO_CREATE_USER:禁止GRANT创建密码为空的用户 NO_ENGINE_SUBSTITUTION:如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常 PIPES_AS_CONCAT:将”||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似 ANSI_QUOTES:启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符

三、解决方法

对于上述示例中的报错,有以下两种思路解决问题。

  1. 关闭only_full_group_by模式(若没有历史数据的情况下不建议关闭该模式)
  2. 官方说明了:You can achieve the same effect without disabling ONLY_FULL_GROUP_BY by using ANY_VALUE() to refer to the nonaggregated column. 您可以在不禁 ONLY_FULL_GROUP_BY用 的情况下通过ANY_VALUE()引用非聚合列来实现相同的效果。

3.1、关闭only_full_group_by模式

3.1.1、方法一:关闭当前会话中的only_full_group_by

在客户端工具中依次输入以下语句

# 查询当前的sql模式 select @@global.sql_mode; # 去除掉only_full_group_by后再设置到系统中 set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';


注意:这种方法只在当前回话中有效,重启mysql后会失效

再次执行本文开头示例中的sql就不会报错了

3.1.2、方法二:永久关闭only_full_group_by模式

(1) 找到配置文件/etc/my.cnf(或则关联文件夹找到mysql-server.cnf)

(2) 找到当前配置的sql_mode那行,去掉ONLY_FULL_GROUP_BY;

如果没有,就在文件内的[mysqld]后增加配置:

sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION''

(3)保存配置文件后,重启Mysql。

如果重启后也不会生效,检查下sql_mode的位置是不是不对(放在最后是不会生效的):

3.2、使用ANY_VALUE()函数

ANY_VALUE():将分到同一组的数据里第一条数据的指定列值作为返回数据。

SELECT any_value(name),age FROM tbl_test group by age;

四、其他

4.1、无权限报错

本人执行

set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

报错了:

[Err] 1227 - Access denied; you need (at least one of) the SUPER privilege(s) for this operation

说明当前用户没有权限;需要联系管理员执行才行;

改服务器配置也同理,如果没有权限,联系管理员。

4.2、select后面的字段必须在group by后面出现?当group by遇上唯一索引或主键

我们上面讲了ONLY_FULL_GROUP_BY模式下select中的列必须在group by中出现,但是经过测试后发现若group by 后面分组字段是唯一索引或者是主键,那么select后面可以跟其他的列

可能看了这句话不太明白,那么我们用示例演示下, 以下示例基于ONLY_FULL_GROUP_BY模式下:

create table tbl_test( id int primary key auto_increment, -- 注意: name是唯一索引字段 name varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci unique not null, age int comment '年龄', address varchar(50) comment '住址', update_time datetime default null ) comment '测试表'; insert into tbl_test(name,age,address,update_time) values ('zhangsan',25,'杭州',now()), ('李四',21,'武汉',now()), ('王五',25,'上海',now());

对上述数据同时查询name与age字段,并根据age字段group by 后报错如下:

因为开启了ONLY_FULL_GROUP_BY模式,分组字段是age但是查询字段里面包含了name,所以报错了。

select后面的字段必须在group by后面出现吗?测试中偶然发现事实并非如此,看下图示例:

可以看到上述示例中,group by后面根据name进行分组,select后面跟了age、address字段但是也没报错。

这是为什么呢?难道group by后面分组字段的值不重复就能跟其他字段么?示例中address字段也是不重复的,那么我们用address进行分组试下,结果报错如下:

经多次测试后发现:若group by后面分组字段是唯一索引或主键字段,那么select 后面可以跟其他字段。

官方文档中也证实了此结论。
官网地址:https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html
官方解释是:当group by 后面跟上主键或者不为空唯一索引时,查询是有效的,因为此时的每一笔数据都具有唯一性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1125590.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Thinkphp和Laravel框架的西安工商学院学生请假管理系统_s4hrg6g5

目录ThinkPHP与Laravel框架的西安工商学院学生请假管理系统项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理ThinkPHP与Laravel框架的西安工商学院学生请假管理系统 该系统基于ThinkPHP或Laravel框架开发,旨在为西安工商学院提供高效的…

小迪安全2023-2024|第13天:信息打点-Web应用源码泄漏开源闭源指纹识别GITSVND_笔记|web安全|渗透测试|网络安全_2023-2024

第13天:信息打点-Web应用&源码泄漏&开源闭源&指纹识别&GIT&SVN&D_笔记 一、信息打点 00:00 1. 业务资产 03:42 1)应用类型分类 开源应用: 定义: 指能够从网上直接下载或已公开的程序源码特点: 通常发布在主流源码平台&#xff0…

Linux下启动redis

一、直接启动redis 使用这种启动方式需要一直打开窗口,不能进行其他操作,按 ctrl c可以关闭窗口。 [rootxxx ~]# cd /usr/local/redis-4.0.6/src [rootxxx src]# ./redis-server二、以后台进程形式启动redis ①设置redis.conf中daemonize为yes&#xff…

从普通产品经理到AI产品经理,你需要掌握的AI思维与核心技能:AI大模型产品经理从零基础到进阶

AI产品经理与普通产品经理的核心区别在于AI思维。人工智能产业链分为基础层、技术层和应用层。AI产品经理可分为突破型、创新型、应用型和普及型四类,需找准定位,避免常见误区。提升能力需专注目标领域,持续学习,扩大交流圈&#…

一文读懂监督、无监督、自监督与半监督学习:小白到大模型必备知识

文章系统介绍机器学习的四大范式:监督学习依赖标注数据训练模型;无监督学习挖掘数据内在特征完成任务;半监督学习结合少量标注和大量无标签数据提升性能;自监督学习通过设计辅助任务从无标签数据中生成监督信号。这些方法各有特点…

10. 同局域网内远程控制另一台电脑

目标: 两台 Windows 家庭版笔记本,在同一 Wi-Fi 下,用 RustDesk 局域网远控 ✅ 不走公网 ✅ 不依赖官方服务器 ✅ 延迟接近本地 ✅ 可扩展到自建服务器一、RustDesk 的“通信模型” 先知道 RustDesk 到底是怎么连的,否则你不知道什…

大模型开发收藏级指南:为什么资深开发者建议先跳过Dify和LangChain?

文章指出,在快速迭代的AI领域,框架往往"约束"大于"赋能"。真正掌握LLM开发应先通过Python调用原生API,以获得更高透明度、更好调试体验和更快适配新特性。建议采用渐进式开发路径:先通过原生API理解基础&…

深度学习毕设选题推荐:基于python-CNN的水果识别基于python的水果识别

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

由continue引发的一个debug灾难

整个代码的简化逻辑是这样的,由于continue的使用含义不清楚,导致debug了半天。这里写代码时,错误的将continue认为是else分支,什么也不干,往下继续执行。 但是这样的理解是极其错误的,continue的意思是跳过…

AI 开源知识库大战:WeKnora、RAGFlow、FastGPT、FlashRAG,谁更厉害

我看大家对目前的开源RAG知识库都挺感兴趣的,就像来对比一下目前比较流行的几个知识库,看看哪个更适合你,哪个更有钱途,哈哈。 其实真要搭过这几个知识库,就会发现:每个用到的地方,还真不一样&a…

Thinkphp和Laravel框架的网上购书图书销售商城系统网站的设计与实现_55ap4swk

目录系统设计背景技术架构功能模块性能与安全总结项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理系统设计背景 ThinkPHP和Laravel作为国内流行的PHP框架,分别以高效开发与优雅设计著称。网上购书商城系统基于两者实现,旨在…

计算机深度学习毕设实战-基于python的水果识别基于python-CNN的水果识别

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

Vue 3 中,unmounted 生命周期钩子会在组件实例被销毁并从 DOM 中移除后调用

Vue3中unmounted钩子在组件销毁时触发,常见场景包括:v-if条件变化;动态组件切换;路由导航;v-for列表更新;父组件卸载;手动调用unmount();Teleport目标移除;组合式API停止…

校平机:金属板材的“应力整形术“

基本原理:消除内应力的力学博弈 校平机是通过塑性弯曲变形来消除金属板材内部残余应力的设备。金属在轧制、切割或热处理后,内部应力分布不均会导致宏观不平整。校平机利用多组交错排列的辊系,使板材经历多次小曲率的正反弯曲,迫…

学习收藏】零门槛上手Ollama:本地大模型部署与实战体验分享

文章详细介绍了本地大模型工具Ollama的安装与使用方法,涵盖Windows和Linux(wsl2)两种环境。作者通过实际测试体验了不同模型的功能,指出本地模型虽功能不及云端大模型,但能满足基本需求且保护隐私。Ollama还提供cloud版本,解决了本…

Linux环境下Tomcat的安装与配置详细指南

Apache Tomcat是一个广泛使用的开源Java Servlet容器和Web服务器,适用于运行Java Web应用程序。本指南将详细介绍如何在Linux环境中安装和配置Tomcat,包括必要的前提条件、下载安装、配置环境变量、设置为系统服务以及基本的安全配置。 目录 前提条件安…

程序员必学!大模型产品经理入门指南(附7阶段学习路线+年薪80万转型案例)

大模型产品经理在2025年迎来黄金发展期,薪资涨幅超50%,一线城市资深年薪突破80万。相比程序员,产品经理凭借场景挖掘、资源整合和产品设计能力可直接切入。文章详解了5大核心能力模型和7阶段学习路线,从认知筑基到实战应用&#x…

Linux系统安装部署Tomcat

1、进入Tomcat官网,官网地址:https://tomcat.apache.org/ 2、点击左侧Download下的Archives按钮 3、选择需要下载的版本 下载地址:https://archive.apache.org/dist/tomcat/ 4、点击自己需要下载的版本,我这里下载的是9.0.6 5、…

AirCloud平台与excloud扩展库协同实战:核心功能落地案例!

在边缘智能与云边协同日益融合的今天,AirCloud平台以其出色的设备管理与资源调度能力脱颖而出,而excloud扩展库则为平台注入了灵活的功能扩展机制。二者的协同应用,为复杂业务场景提供了强有力的支撑。但如何通过合理配置实现功能最大化&…

uvm_config_db机制学习

1. 当uvm_config_db传递一个类的句柄时,传递的是这个句柄,如果有组件在后续的phase中,改变了对象的值,那么其他组件也能感知到这个对象的值发生了变化并不是在build_phase阶段,这个句柄被set了之后,值就不会…