一文彻底说清楚MySQL报1055 - SELECT list is not in GROUP BY incompatible with sql_mode=only_full_group_by的问题

2023-11-10

先说结论

        这个问题根本原因是SQL不严谨造成的,由于5.7版本之前没有严格限制所以没有报错,但5.7之后默认进行了限制,需要DBA根据实际生产情况决定是忽略该错误,还是优化SQL解决该错误。

        如果是要忽略该错误,那么就把5.7版本加入的默认限制给去掉即可,即把SQL_MODE中的“ONLY_FULL_GROUP_BY”给去掉,而如果是要优化SQL来解决问题,就需要稍微花点功夫来分析你的SQL,具体分析方法下文会举个简单栗子来进行说明。

产生原因

        开发中常常遇到各种各样的错误,解决办法往往也有多种,大致有“掩盖法”、“间接解决法”、“直接解决法”。使用“掩盖法”迟早会在其他时候或其他场景爆出更严重的问题,得不偿失;而“间接解决法”虽然能解决目前的问题,但却是知其然而不知其所以然,往往解决代码的可读性和可理解性都不高,甚至是引入了其他潜在的bug;所以最合适的当然是“直接解决法”,但直接解决问题需要刨根问题,深入了解根本原因,需要耗费时间和精力,所以这也是打磨好产品的一个根基,是慢慢磨出来的。

        言归正传,我举个小栗子来说明原因。

CREATE TABLE tbl_a (
  id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  a_name VARCHAR(20) NOT NULL COMMENT 'a名称',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='a表';

CREATE TABLE tbl_b (
  id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `code` varchar(32) NOT NULL COMMENT '唯一编码',
  b_name VARCHAR(20) NOT NULL COMMENT 'b名称',
  PRIMARY KEY (id),
	UNIQUE KEY uni_code (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='b表';

CREATE TABLE tbl_c (
  id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  c_name VARCHAR(20) NOT NULL COMMENT 'c名称',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='c表';

CREATE TABLE tbl_d (
  id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `code` varchar(32) NOT NULL COMMENT 'b编码',
  a_id BIGINT(20) NOT NULL COMMENT 'aID',
  c_name VARCHAR(20) NOT NULL COMMENT 'c名称',
  d_name VARCHAR(20) NOT NULL COMMENT 'd名称',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='d表';

CREATE TABLE tbl_e (
  id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  d_id BIGINT(20) NOT NULL COMMENT 'dID',
  e_name VARCHAR(20) NOT NULL COMMENT 'e名称',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='e表';

        创建5个表,其中a、b、c都是基础信息表,d、e表是一个综合信息表,它因为关联了基础信息表中的某个字段而建立了关联关系。

        现在我们执行下面这个SQL,大家看看执行结果会怎样?

SELECT a.*, b.*, c.id, d.*, e.*
FROM tbl_d d
LEFT JOIN tbl_c c ON c.c_name = d.c_name
LEFT JOIN tbl_b b ON b.`code` = d.`code`
LEFT JOIN tbl_a a ON a.id = d.a_id
LEFT JOIN tbl_e e ON e.d_id = d.id
GROUP BY d.id;

结果是
> 1055 - Expression #11 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'ppay.c.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
> 时间: 0.042s

        那这个SQL,执行结果又会怎样呢?

SELECT a.*, b.*, d.*
FROM tbl_d d
LEFT JOIN tbl_c c ON c.c_name = d.c_name
LEFT JOIN tbl_b b ON b.`code` = d.`code`
LEFT JOIN tbl_a a ON a.id = d.a_id
LEFT JOIN tbl_e e ON e.d_id = d.id
GROUP BY d.id;

结果是
> OK
> 时间: 0.043s

        这个SQL,执行结果又会怎样呢?

SELECT a.*, b.*, c.id, d.*, e.*
FROM tbl_d d
LEFT JOIN tbl_c c ON c.c_name = d.c_name
LEFT JOIN tbl_b b ON b.`code` = d.`code`
LEFT JOIN tbl_a a ON a.id = d.a_id
LEFT JOIN tbl_e e ON e.d_id = d.id
GROUP BY c.id, d.id, e.id;

结果是
> OK
> 时间: 0.043s

        这个SQL,执行结果又会怎样呢?

SELECT a.*, b.*, ANY_VALUE(c.id), d.*, e.*
FROM tbl_d d
LEFT JOIN tbl_c c ON c.c_name = d.c_name
LEFT JOIN tbl_b b ON b.`code` = d.`code`
LEFT JOIN tbl_a a ON a.id = d.a_id
LEFT JOIN tbl_e e ON e.d_id = d.id
GROUP BY d.id, e.id;

结果是
> OK
> 时间: 0.042s

        为什么呢?

        从错误的字面意思看就是SELECT的字段和GROUP BY的字段不能进行逻辑上的依赖推导,大白话就是GROUP BY分组后某些字段可能存在多条,MySQL不清楚应该取哪个,再加上SQL_MODE的限制,就直接报错了。(官方错误码手册

        那为什么后面几个SQL又能执行成功呢?其实本质上就是解决了不能进行依赖推导的问题,只是解决办法有多种。

        第一种很好理解,我们把SELECT的字段中去掉会产生歧义的;第二种则是既然SELECT存在歧义,那分组的时候我就捎带上你,让你不存在歧义;第三种是明知道有歧义了,但这个歧义产生的后果我不关心,你随意返回个值就行;

        接下来再说说为什么对d表的id进行分组时,a、b表不会产生歧义,而c、e表会产生歧义呢?因为d表中存储的是a表的id,即一个d.id是可以唯一推导出一个a.id的,同理,对于b表来说,存储的是含有唯一索引的code字段,通过一个d.id也可以唯一推导出一个b.code。但是对于c表来说存储的是普通字段name,一个d.id是可以推导出无数个b.name的。看到这里你可能会有疑问,e表不就是存储的d表的id吗,怎么还是存在歧义?答案很简单,因为依赖关系是反的,通过e.id是可以推导出唯一一个d.id,但是通过d.id却无法推导出唯一一个e.id。

写在最后

        到这里相信聪明的你已经能根据实际生产场景来优化你的SQL了,我想再说说文章开头说的那种“忽略错误”的解决方式,即通过去掉“ONLY_FULL_GROUP_BY”来解决问题的方法。因为当时给同事说了解决办法,他说修改了但是没有生效,下面针对该方法具体说明下,以及最佳实践应该是怎么样的。

        MySQL是一个多线程应用,对建立每个建立的连接都会新开启一个线程,每一个线程都会有一个会话session,里面保存了该会话特有的配置,其中就包括本文讨论的“ONLY_FULL_GROUP_BY”。那会话中的配置是从哪儿来的呢?答案是从全局配置中读取的,所以当开启一个全新会话的时候,其配置是完全来自全局配置的。那全局配置又是从哪儿来的呢?答案是MySQL配置文件(linux的*.cnf文件,windows的*.ini文件),里面有关于SQL_MODE的配置项,服务启动时就是通过该值进行初始化的。好,看到这里,相信你应该知道改哪些值需要重启哪些东西了,即:

        修改全局配置,则只需要断开并重新连接,建立新的会话即可,但是MySQL服务重启后仍然会回滚(断开重新连接,对于Web服务来说,就是重启Web服务),而修改会话配置则千万不要断开重连(即对于Web服务来说,千万别重启服务),否则又使用全局配置了,最后如果是修改配置文件的话,则需要重启MySQL才能生效。

        综上,最佳实践应该是修改MySQL配置文件中的配置项,并且修改全局配置项,这样只需要断开并重新连接,建立新的会话即可立即生效。

        have a nice time!(原文链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文彻底说清楚MySQL报1055 - SELECT list is not in GROUP BY incompatible with sql_mode=only_full_group_by的问题 的相关文章

随机推荐

  • c语言编程请增补函数fun

    题目 填空题 请增补函数fun 该函数的功能是 把从主函数中输入的字符串str2接在字符串str2的背面 例似 str2 How do str2 you do 结论输出 How do you do 试题程序 include include
  • 第十二届蓝桥杯国赛-H:和与乘积-python

    一 问题描述 二 问题分析 对于输入的一个数列 求这个数列的满足以下条件的区间个数 该区间的元素和与元素积相等 思路就是计算每一个区间的元素和与元素积 如果相等就计数加一 获取每个区间采用前缀和跟前缀积的方法 详见代码 注 这种方法也只能通
  • Sass语法学习

    1 编译监控 自动监控把sass编译成css文件 命令行 sass watch sass basic scss css basic css 在监控的sass后面 可以为 sass 生成 css 样式指定生成的格式 默认是nested型 st
  • 手机端网页:可拖拽悬浮按钮

    div style width 60px height 60px img src im div
  • cesium for unreal文档中的更新

    以前调试过cesium for unreal 再调试时一惊 发现api变了 静下心来思考流程 1 样本条要放在actor里 2 包含样本条的actor坐标放在原点 3 样本条坐标和法向量都要从经纬高到ue空间转换 变的只是api 所以深入了
  • 服务端架构:Mybatis-Plus的优缺点

    前段时间帮朋友处理java后端架构问题 看到了mybatis plus 其实早几年就知道这个东西 但一直没用没学 这两天许久未见的web服务看了看 聊聊个人感受 如有不适 请见谅 文章目录 优点 缺点 1 对数据访问层DAO的上层入侵太强
  • 死锁算法:银行家算法和安全性算法

    死锁算法 银行家算法和安全性算法 借鉴了一些文章 自己总结了一下 银行家算法 首先 算法的核心在于 每次进程申请资源时 都会进行一次试探性分配 若成功 则真实分配 基本思想 在每个新进程进入系统时 他必须声明在运行过程中 可能需要的每种资源
  • 多线程(重点)

    进程和线程的区别 1 根本区别 进程是操作系统进行资源分配的最小单元 线程是操作系统进行运算调度的最小单元 2 从属关系不同 进程中包含了线程 线程属于进程 3 开销不同 进程的创建 销毁和切换的开销都远大于线程 4 拥有资源不同 每个进程
  • 高性能计算实验——矩阵乘法基于MPI的并行实现及优化

    高性能计算实验 矩阵乘法基于MPI的并行实现及优化 1 实验目的 1 1 通过MPI实现通用矩阵乘法 1 2 基于MPI的通用矩阵乘法优化 1 3 改造实验1成矩阵乘法库函数 2 实验过程和核心代码 2 1 通过MPI实现通用矩阵乘法 2
  • 【Git学习】6.分支(branch)创建、修改与合并

    查看log 附带 graph可以查看其他分支 建立分支 branch dev 查看分支 有 说明HEAD指针在master分支 用checkout指令把指针切换到dev 查看分支 直接checkout b指令 可以省略上述步骤 直接创建并切
  • Java file outside of soure root 导入项目时idea无法识别为java文件

    一 问题描述 今天一个小师弟私信我 导入别人的项目时 idea没有识别出是Java项目 Java file outside of soure root 二 解决 在idea重新设置一下就好了 1 打开File gt Project Stru
  • 阿里云—(1)安装JDK 11

    1 查看原有JDK版本 若新装系统 可忽略 yum list installed grep java 如图所示 代表已安装 2 查看yum库内所有的JDK版本 yum y list java 当你已经安装了某个版本后 显示的为本地安装包 下
  • MySQL调优学习笔记(三):组合索引和函数索引

    目录 什么是组合索引 组合索引的优势 什么是函数索引 函数索引的优势 总结 参考资料 姜承尧的MySQL实战宝典 什么是组合索引 组合索引是指由多个列所组合而成的B 树索引 组合索引既可以是主键索引 也可以是二级索引 组合索引 a b 和组
  • python3爬虫系列之使用requests爬取LOL英雄图片

    我们最终目的就是要把抓取到的图片保存到本地 所以先写一个保存图片的方法 可以保存任何二进制文件 注意在windows下文件命名包含 可能会发生错误 有的英雄皮肤名称确实包含 所以这里使用正则表达式替换下 方法包含文件路径 文件名称 文件内容
  • 多益网络社招iq_多益网络2018秋招iq测试题(二)

    我也来发一下我的秋招笔试题 不知道能不能收到礼物 1 从所给选项中选一个最合适的填入问号处使其呈现一定规律 A A B B C C D D E E 2 一个人花8块钱买了一只鸡 9块钱卖掉了 然后他觉得不划算 花10块钱又买回来了 11块卖
  • Prometheus+Grafana监控K8S 监控pod的解决方案(监控 java-JVM-pod)

    prometheus 监控 k8s pod 容器服务状态 Prometheus Grafana 作为监控K8S的解决方案 大部分都是在K8S集群内部部署 所以监控起来很方便 可以直接调用集群内的cert及各种监控url 但是增加了集群的资源
  • 杭电OJ 1071(C++)

    纯数学题 定积分 include
  • 功率放大电路

    1 什么是功率放大电路 功率放大电路与电压放大电路的主要区别是要求电路向负载提供足够大的输出功率 特点是 功率放大电路的输出电压和输出电流都应足够大的变化 其次是具有较高的效率 在功率放大电路主要解决的问题是 三极管通常工作在大信号状态 使
  • Qt使用事件(event)与定时器实现字幕滚动

    目录 1 效果展示 2 实现思路 3 滚动窗口部件 3 1 成员变量 3 2 事件重写 3 3 成员方法 3 3 方法实现 1 效果展示 我们经常能够在外面看到那种滚动字幕 那么就拿qt来做一个吧 2 实现思路 实现一个窗口部件 这个窗口部
  • 一文彻底说清楚MySQL报1055 - SELECT list is not in GROUP BY incompatible with sql_mode=only_full_group_by的问题

    先说结论 这个问题根本原因是SQL不严谨造成的 由于5 7版本之前没有严格限制所以没有报错 但5 7之后默认进行了限制 需要DBA根据实际生产情况决定是忽略该错误 还是优化SQL解决该错误 如果是要忽略该错误 那么就把5 7版本加入的默认限