MySQL 不同版本下的group by

MySQL 不同版本下的group by

    大家有没有遇到过这样的坑,在把MySQL升级到更高的版本,一些以前看上去不会出错的group by 操作在这个版本以后就会出现语法报错的情况。这里就来记录下我在使用mysqll分组查询所遇到的坑。

 1 # 创建一张表,并插入几条数据
 2 
 3 
 4 CREATE TABLE `student` (
 5     `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 6     `name` varchar(8) NOT NULL,
 7     `sex` varchar(2) NOT NULL,
 8     `birthday` date DEFAULT NULL,
 9     `class_id` int(10) unsigned NOT NULL COMMENT '班级Id',
10     PRIMARY KEY (`id`),
11     KEY `class_id` (`class_id`)
12 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
13 
14 INSERT INTO `student` (`name`, `sex`, `birthday`, `class_id`)
15 VALUES ('文芳', '', '1976-02-20', '95033'),
16     ('张强', '', '1974-06-03', '95031'),
17     ('赵星', '', '1975-10-02', '95031'),
18     ('王丽', '', '1976-01-23', '95033'),
19     ('曾华', '', '1977-09-01', '95033'),
20     ('王芳', '', '1975-02-10', '95031');

      然后,我们看到表里面已经有数据:

   

1 select * from `student` group by `class_id`
2 
3 报错信息:Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'student.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

   但是,当sql改成下面这样,就能够正常进行查询,返回结果 :

1  select * from `student` group by `id`
2 
3  select id , name  from `student` group by `id`

   分析:

   1)当group by 后面这个字段是主键时,id 便与 select 后面选择的字段均产生了一种关系即 id 可确定唯一 一条记录。此时便可进行 GROUP BY 了。因为,之所以报错是因为在进行聚合的时候有不能确定的列参与了进来。

   2)5.7.5之前,MySQL没有检测到功能依赖关系,默认情况下不启用ONLY_FULL_GROUP_BY。MySQL 5.7.5及以上功能依赖检测功能,默认情况启用了ONLY_FULL_GROUP_BY。

   总结

   1)由于开启了ONLY_FULL_GROUP_BY的设置,select后面跟着的字段,要全部在group by后面跟着。

   2)如果一个字段没有在select 后面和group by字段中同时出现,或者该字段不是聚合函数(AVG,COUNT,SUM,MAX和MIN)的参数的话,那么这条sql查询是被mysql认为非法的,会报错误。

   下面是当我们遇到这种报错情况时,总结的一些排查过程和解决方法。

    一、查询mysql版本

    首先,我们要知道我们之前用的MySQL和现在用的版本各是多少?

1 # 方式一:
2 select version();
3 
4 # 方式二:
5 show variables like '%version%';

    升级前查询到的mysql版本为:5.7.32-log,升级后查询到的mysql版本为:8.0.18

    不知道大家是否像我一样有疑问,为什么后面加了-log后缀呢?

# MySQL作者Paul DuBois的解释是:
I want to know what the -log means and how it got in there.

如果在启用日志记录的情况下启动服务器,则会添加-log.

如果您正在运行调试版本的服务器,则会添加-debug.

如果服务器在演示模式下运行,则添加-demo

  在源代码 sql/mysqld.cc中,函数set_server_version():

  ...

  if (opt_log || opt_slow_log || opt_bin_log)

  strmov(end, "-log"); // This may slow down system

  ...

  说明:“This may slow down system” 该注释的含义并不是在版本中添加四个额外字符会降低系统速度,但是日志记录可能会降低系统速度,因此值得注意的是DBA启用了日志记录

   二、 解决办法

   1.  关闭 ONLY_FULL_GROUP_BY

   1)查看sql_mode

1 # 执行查询语句
2 
3 SELECT @@sql_mode;
4 
5 # 查询结果:
6 
7 ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

    2)方式一:通过以下脚本关闭

1 SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY,',''));

   上面这种方式数据库重启后设置会失效,只是修改了内存中的值,不能永久改变。想要永久解决需要在配置文件中修改。

   3) 方式二:配置文件修改

    Windows下MySQL的配置文件是 my.ini,一般会在安装目录的根目录。

    Linux下MySQL的配置文件是my.cnf,一般位置为 /etc/my.cnf

# 在【mysqld】下面添加:
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
 
# 然后,重启mysql
service mysqld restart

   

     但是,因为 ONLY_FULL_GROUP_BY 更加符合 SQL 标准,所以不建议关掉。

 

 参考链接:https://www.cnblogs.com/Wayou/p/mysql_group_by_issue.html

posted @ 2021-12-31 13:18  欢乐豆123  阅读(637)  评论(0编辑  收藏  举报