mysql报错:

  1. 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+ 的默认设置。它要求 SELECTHAVINGORDER BY 子句中的列,要么必须出现在 GROUP BY 子句中,要么必须包含在聚合函数(如 MAX(), SUM())中。
    • 影响:如果不遵守,MySQL 会报错(如 Error 1055)。关闭它虽然能运行,但查出来的非聚合列数据可能是随机的、不确定的。

💻 兼容性与特殊行为类

这些参数通常用于兼容旧系统或其他数据库标准。

参数名称 作用说明 典型场景
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_TABLESSTRICT_ALL_TABLESNO_ZERO_IN_DATENO_ZERO_DATEERROR_FOR_DIVISION_BY_ZERO 等一系列严格限制。
  • 适用性:如果你希望 MySQL 的行为尽可能接近标准 SQL 且极其严格,可以使用这个模式。

💡 最佳实践建议

对于大多数现代 Web 应用,推荐的生产环境配置通常是以下组合(兼顾严格性与可用性):

  1. [mysqld]
  2. # 严格模式 + 禁止零日期 + 除零报错 + 禁止引擎替换 + 严格的 GROUP BY
  3. sql_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 要求 SELECTHAVINGORDER BY 子句中出现的任何列都必须满足以下两个条件之一:

  1. 该列必须出现在 GROUP BY 子句中。
  2. 该列必须被包裹在聚合函数(如 SUM(), COUNT(), MAX(), MIN() 等)中。

你的报错信息明确指出,ORDER BY 子句中的 ticketdb.m.sort 字段既不在 GROUP BY 中,也没有使用聚合函数,因此触发了这个严格的检查。

🎯 解决方案

你可以通过以下几种方式来解决这个问题,推荐优先考虑修改 SQL 语句。

方案一:修改 SQL 语句

这是最规范的做法,能让你的 SQL 逻辑更清晰,并且兼容所有数据库。

  • 方法 A: 将排序字段加入 GROUP BY 如果你的业务逻辑允许,可以将 m.sort 字段添加到 GROUP BY 子句中。

    1. -- 假设你的原始SQL类似这样
    2. SELECT m.category_id, m.name
    3. FROM tickets m
    4. GROUP BY m.category_id
    5. ORDER BY m.sort; -- 这里会报错
    6. -- 修改为
    7. SELECT m.category_id, m.name
    8. FROM tickets m
    9. GROUP BY m.category_id, m.sort -- m.sort 加入 GROUP BY
    10. ORDER BY m.sort;
  • 方法 B: 对排序字段使用聚合函数 如果你只是想按分组的某个值来排序,可以使用 MAX()MIN() 等聚合函数。

    1. -- 修改为
    2. SELECT m.category_id, m.name
    3. FROM tickets m
    4. GROUP BY m.category_id
    5. ORDER BY MAX(m.sort); -- 使用聚合函数包裹 m.sort

方案二:临时禁用 ONLY_FULL_GROUP_BY 模式

这种方法可以快速解决问题,但不推荐在生产环境中长期使用,因为它可能会掩盖 SQL 语句潜在的逻辑问题,导致查询结果不确定。

你可以在当前的数据库连接会话中执行以下命令来临时关闭它:

  1. # 先查询
  2. -- 查看全局配置,确认已包含你想要的模式
  3. SELECT @@GLOBAL.sql_mode;
  4. -- 建议也检查一下当前会话,新建立的连接应该与全局配置一致
  5. SELECT @@SESSION.sql_mode;
  6. # 再设置,移除【ONLY_FULL_GROUP_BY】
  7. SET SESSION sql_mode = (SELECT REPLACE(@@SESSION.sql_mode, 'ONLY_FULL_GROUP_BY', ''));

执行后,你原来的 SQL 语句就可以正常运行了。但这个设置只在当前连接中有效,断开重连后会失效。

方案三:永久禁用 ONLY_FULL_GROUP_BY 模式

需要修改 MySQL 的配置文件 (my.cnfmy.ini)。

  1. 找到并编辑 MySQL 的配置文件,在【[mysqld]】下添加如下代码(表示移除“ONLY_FULL_GROUP_BY”):
  1. [mysqld]
  2. sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
  1. 保存文件并重启 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