MySQL ONLY_FULL_GROUP_BY

内容目录

MySQL ONLY_FULL_GROUP_BY

场景

在开发环境中遇到一个报错:

Error querying database.  Cause: java.sql.SQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'your_column' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

报错信息基本说明了是因为你的SQL与SQL Mode不兼容,其中关键是sql_mode=only_full_group_by。

为什么会报错?

MySQL 版本默认启用了only_full_group_by并且SQL并没有遵循SQL-92标准的话,MySQL 5.7.5及以后版本会检测这个场景,如果only_full_group_by SQL模式被启用,那么MySQL会直接报错。

  • only_full_group_by这个SQL Mode在MySQL中默认是启用的,可以使用 select @@global.sql_mode;来查询MySQL的SQL Mode,只有返回的结果中有only_full_group_by就表示被启用。

    什么是only_full_group_by?

    在SQL-92或者更早的标准中,SELECT语句有group by从句时,如果having条件或者order by的字段列表包含有group by 从句中没有的条件,那么SQL执行就会报错。
    在SQL 1999标准则允许group by从中没有的条件在select列表中出现。
    例如:

    SELECT o.custid, c.name, MAX(o.payment)
    FROM orders AS o, customers AS c
    WHERE o.custid = c.custid
    GROUP BY o.custid;
    # 根据SQL-92标准,SELECT列表中的username必须在group by 从句中
    # 根据SQL 1999标准,上面这个SQL语句是合法的。

复现

MySQL 版本: 8.0

表结构

表DDL语句如下:

CREATE TABLE `user_balance` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` bigint NOT NULL COMMENT '用户ID',
  `username` varchar(32) NOT NULL COMMENT '用户名',
  `balance` bigint NOT NULL COMMENT '余额, 单位:分',
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '用户余额';

-- 插入6条记录
INSERT INTO `user_balance` (`user_id`, `username`, `balance`) VALUES (1, '张三', 1);
INSERT INTO `user_balance` (`user_id`, `username`, `balance`) VALUES (2, '李四', 1);
INSERT INTO `user_balance` (`user_id`, `username`, `balance`) VALUES (3, '王五', 1);
INSERT INTO `user_balance` (`user_id`, `username`, `balance`) VALUES (4, '张大麻子', 1);
INSERT INTO `user_balance` (`user_id`, `username`, `balance`) VALUES (5, '李二麻子', 1);
INSERT INTO `user_balance` (`user_id`, `username`, `balance`) VALUES (6, '王三麻子', 1);

错误复现

select user_id, username, sum(balance) from user_balance group by user_id;

错误输出:

ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'fullgroupby.user_balance.username' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

怎么解决?

方式1-修改全局变量

这种方式在数据库重启后会失效,所以使用这种方式在重启数据库后需要再次执行更改sql_mode。
查询当前sql_mode,然后删除返回sql_mode字符串中的only_full_group_by,再设置sql_mode全局变量。

select @@global.sql_mode;

+-----------------------------------------------------------------------------------------------------------------------+
| @@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 |
+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

将查询出来的sql_mode复制出来,删除掉,然后执行

# 
set 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 ';
Query OK, 0 rows affected (0.00 sec)

方式2-修改my.cnf

在my.cnf文件的[mysqld]模块下新增sql_mode配置

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

方式3-使用any_value()函数

如果你不想修改sql_mode,但是又想使用到SQL 1999标准, 那么就使用any_value()函数。MySQL提供了any_value函数用来告诉MySQL不要拒绝执行这类SQL。

select user_id, any_value(username), sum(balance) from user_balance group by user_id;
+---------+---------------------+--------------+
| user_id | any_value(username) | sum(balance) |
+---------+---------------------+--------------+
|       1 | ??                  |            1 |
|       2 | ??                  |            1 |
|       3 | ??                  |            1 |
|       4 | ????                |            1 |
|       5 | ????                |            1 |
|       6 | ????                |            1 |
+---------+---------------------+--------------+
6 rows in set (0.00 sec)

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部