MySql--ONLY_FULL_GROUP_BY

摘要

ONLY_FULL_GROUP_BY

  • MySql5.7.5及以上版本将sql_modeONLY_FULL_GROUP_BY模式默认设置为打开状态,会导致一些错误

  • 当使用GROUP BY查询时,出现在SELECT字段后面的只能是GROUP BY后面的分组字段,或使用聚合函数包裹着的字段,否则会报错如下信息:

1
Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'database.table.column' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
  • 当使用ORDER BY查询时,不能使用SELECT DISTINCT去重查询。否则会报错如下信息:

1
Expression #1 of ORDER BY clause is not in SELECT list, references column 'database.table.column' which is not in SELECT list; this is incompatible with DISTINCT

禁用ONLY_FULL_GROUP_BY

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 查询
mysql> select version(), @@sql_mode;
+-----------+-----------------------------------------------------------------------------------------------------------------------+
| version() | @@sql_mode |
+-----------+-----------------------------------------------------------------------------------------------------------------------+
| 8.0.30 | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------+-----------------------------------------------------------------------------------------------------------------------+

# name 不在group by 中,则报错
mysql> select update_time,name,count(*) from actor group by update_time;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.actor.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

# name 在group by中时,查询正常
mysql> select update_time,name,count(*) from actor group by update_time,name;
+---------------------+------+----------+
| update_time | name | count(*) |
+---------------------+------+----------+
| 2017-12-22 15:27:18 | a | 1 |
| 2017-12-22 15:27:18 | b | 1 |
| 2017-12-22 15:27:18 | c | 1 |
+---------------------+------+----------+

# DISTINCTORDER BY 查询时报错
mysql> select DISTINCT(t.name) FROM tbl_test t where t.id = 28 ORDER BY t.create_time desc LIMIT 6;
(3065, "Expression #1 of ORDER BY clause is not in SELECT list, references column 'testdb.t.create_time' which is not in SELECT list; this is incompatible with DISTINCT")

# 禁用ONLY_FULL_GROUP_BY
mysql> SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

# 再次查询,结果正常,注意这里name只会保留分组结果中第一条记录的值
mysql> select update_time,name,count(*) from actor group by update_time;
+---------------------+------+----------+
| update_time | name | count(*) |
+---------------------+------+----------+
| 2017-12-22 15:27:18 | a | 3 |
+---------------------+------+----------+

# 永久禁用
my.cnf中[mysqld]中添加
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

以下为sql_mode常用值的含义

1
2
3
4
5
6
7
8
9
10
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后,不能用双引号来引用字符串,因为它被解释为识别符

也可是使用 ANY_VALUE()函数 来解决查询属性没有出现在group by中的情况,此时即使没有禁用ONLY_FULL_GROUP_BY也不会报错。

1
2
3
4
5
6
select update_time,any_value(name),count(*) from actor group by update_time;
+---------------------+-----------------+----------+
| update_time | any_value(name) | count(*) |
+---------------------+-----------------+----------+
| 2017-12-22 15:27:18 | a | 3 |
+---------------------+-----------------+----------+