mysql报错:
SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'oa_api.oa_form_cloud_project_daily.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
MySQL 的 sql_mode 就像是一个“交通指挥中心”,它决定了 MySQL 应该如何处理数据校验、语法兼容性以及错误容忍度。
针对你刚才遇到的 ONLY_FULL_GROUP_BY 问题,以及其他常见的开发场景,我为你整理了 sql_mode 中最常用、影响最大的参数及其具体作用:
🛡️ 严格性与数据校验类(核心参数)
这些参数主要用于保证数据的准确性和完整性,防止“脏数据”入库。
| 参数名称 | 作用说明 | 典型场景与影响 |
|---|---|---|
| STRICT_TRANS_TABLES | 严格模式。如果插入的数据不符合列定义(如类型不匹配、非空列为空),直接报错并回滚事务。 | 生产环境必开。不开启时,MySQL 会尝试将非法数据截断或转换为默认值(如插入字符串 ‘abc’ 到 int 字段变为 0),这非常危险。 |
| NO_ZERO_DATE | 禁止插入 '0000-00-00' 这种零日期。 |
防止因程序逻辑错误导致的时间戳初始化问题。 |
| NO_ZERO_IN_DATE | 禁止日期中的月或日为 0(例如 '2023-00-01')。 |
进一步确保日期的合法性。 |
| ERROR_FOR_DIVISION_BY_ZERO | 当进行除以零的操作时,直接抛出错误,而不是返回 NULL。 |
帮助开发者快速发现代码中的逻辑漏洞。 |
| NO_ENGINE_SUBSTITUTION | 如果建表时指定的存储引擎(Engine)不存在或被禁用,直接报错,而不是自动替换为默认引擎(如 InnoDB)。 | 避免因引擎意外变更导致的性能下降或功能缺失。 |
📊 SQL 语法与聚合类
这类参数直接影响 SQL 语句的写法,也是你之前遇到报错的根源。
- ONLY_FULL_GROUP_BY
- 作用:这是 MySQL 5.7+ 的默认设置。它要求
SELECT、HAVING或ORDER BY子句中的列,要么必须出现在GROUP BY子句中,要么必须包含在聚合函数(如MAX(),SUM())中。 - 影响:如果不遵守,MySQL 会报错(如 Error 1055)。关闭它虽然能运行,但查出来的非聚合列数据可能是随机的、不确定的。
- 作用:这是 MySQL 5.7+ 的默认设置。它要求
💻 兼容性与特殊行为类
这些参数通常用于兼容旧系统或其他数据库标准。
| 参数名称 | 作用说明 | 典型场景 | ||
|---|---|---|---|---|
| ANSI_QUOTES | 将双引号 " 视为标识符(如表名、列名)的引用符,而不是字符串。 |
从 Oracle 或 PostgreSQL 迁移到 MySQL 时常需开启,因为这些数据库用双引号表示字段名。 | ||
| PIPES_AS_CONCAT | 将 ` | 视为字符串连接符(类似CONCAT()`),而不是逻辑 OR 运算符。 |
同样是为了兼容 Oracle 等数据库的标准 SQL 语法。 | |
| IGNORE_SPACE | 允许函数名和括号之间有空格(如 COUNT (*))。 |
默认情况下 MySQL 认为这是语法错误,开启后更宽容。 | ||
| PAD_CHAR_TO_FULL_LENGTH | CHAR 类型的字段在检索时会填充空格到全长。 |
改变 CHAR 字段的比较行为,使其符合标准 SQL。 |
⚠️ 一个特殊的组合模式:TRADITIONAL
你可能还会看到有人推荐设置 TRADITIONAL 模式。
- 注意:这并不是一个独立的参数,而是一个组合包。
- 包含内容:它等同于同时开启了
STRICT_TRANS_TABLES、STRICT_ALL_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO等一系列严格限制。 - 适用性:如果你希望 MySQL 的行为尽可能接近标准 SQL 且极其严格,可以使用这个模式。
💡 最佳实践建议
对于大多数现代 Web 应用,推荐的生产环境配置通常是以下组合(兼顾严格性与可用性):
[mysqld]# 严格模式 + 禁止零日期 + 除零报错 + 禁止引擎替换 + 严格的 GROUP BYsql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY
注:MySQL 8.0 之后,官方默认的 sql_mode 已经去掉了部分过时的限制(如 NO_AUTO_CREATE_USER),但在实际运维中,保持上述严格配置依然是防止数据事故的最佳手段。
这个错误是 MySQL 5.7 及以上版本中一个非常常见的问题,根本原因在于 sql_mode 默认开启了 ONLY_FULL_GROUP_BY 模式。
简单来说,当你的 SQL 语句中使用了 GROUP BY 时,MySQL 要求 SELECT、HAVING 或 ORDER BY 子句中出现的任何列都必须满足以下两个条件之一:
- 该列必须出现在
GROUP BY子句中。 - 该列必须被包裹在聚合函数(如
SUM(),COUNT(),MAX(),MIN()等)中。
你的报错信息明确指出,ORDER BY 子句中的 ticketdb.m.sort 字段既不在 GROUP BY 中,也没有使用聚合函数,因此触发了这个严格的检查。
🎯 解决方案
你可以通过以下几种方式来解决这个问题,推荐优先考虑修改 SQL 语句。
方案一:修改 SQL 语句
这是最规范的做法,能让你的 SQL 逻辑更清晰,并且兼容所有数据库。
方法 A: 将排序字段加入 GROUP BY 如果你的业务逻辑允许,可以将
m.sort字段添加到GROUP BY子句中。-- 假设你的原始SQL类似这样SELECT m.category_id, m.nameFROM tickets mGROUP BY m.category_idORDER BY m.sort; -- 这里会报错-- 修改为SELECT m.category_id, m.nameFROM tickets mGROUP BY m.category_id, m.sort -- 将 m.sort 加入 GROUP BYORDER BY m.sort;
方法 B: 对排序字段使用聚合函数 如果你只是想按分组的某个值来排序,可以使用
MAX()或MIN()等聚合函数。-- 修改为SELECT m.category_id, m.nameFROM tickets mGROUP BY m.category_idORDER BY MAX(m.sort); -- 使用聚合函数包裹 m.sort
方案二:临时禁用 ONLY_FULL_GROUP_BY 模式
这种方法可以快速解决问题,但不推荐在生产环境中长期使用,因为它可能会掩盖 SQL 语句潜在的逻辑问题,导致查询结果不确定。
你可以在当前的数据库连接会话中执行以下命令来临时关闭它:
# 先查询-- 查看全局配置,确认已包含你想要的模式SELECT @@GLOBAL.sql_mode;-- 建议也检查一下当前会话,新建立的连接应该与全局配置一致SELECT @@SESSION.sql_mode;# 再设置,移除【ONLY_FULL_GROUP_BY】SET SESSION sql_mode = (SELECT REPLACE(@@SESSION.sql_mode, 'ONLY_FULL_GROUP_BY', ''));
执行后,你原来的 SQL 语句就可以正常运行了。但这个设置只在当前连接中有效,断开重连后会失效。
方案三:永久禁用 ONLY_FULL_GROUP_BY 模式
需要修改 MySQL 的配置文件 (my.cnf 或 my.ini)。
- 找到并编辑 MySQL 的配置文件,在【[mysqld]】下添加如下代码(表示移除“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
- 保存文件并重启 MySQL 服务以使配置生效。
重启数据库(也许不用,待验证): systemctl restart mysqld
⚙️ 不同版本的默认配置差异
如果你发现测试环境和生产环境的参数不一样,可能是因为 MySQL 版本不同。以下是官方默认的“出厂设置”对比:
- MySQL 5.6 及以下:
- 默认为空(非常宽松,容易埋下数据隐患)。
- MySQL 5.7:
- 默认开启:
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
- 默认开启:
- MySQL 8.0+:
- 默认开启:
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION - 注:8.0 移除了
NO_AUTO_CREATE_USER。
- 默认开启:
