1.问题
最近公司项目在部署到甲方环境时,出现了一个sql查询的问题
这个错误大概的意思就是:
SELECT列表的表达式不在GROUP BY子句和中
包含非聚合列'。。”不依赖于GROUP BY子句中的列;
这是与SQL模式=only不兼容。
2.原因
官方是这样解释的:
MySQL 5.7.5及更高版本实现了函数依赖性的检测。如果启用了ONLY_FULL_GROUP_BY SQL模式(默认情况下是这样),MySQL将拒绝select列表、HAVING条件或ORDER by列表引用既不在GROUP by子句中命名也在功能上依赖于它们的非聚合列的查询。(在5.7.5版本之前,MySQL不检测函数依赖性,并且默认没有启用ONLY_FULL_GROUP_BY。有关5.7.5之前行为的描述
大概意思就是:因为数据库版本的问题,sql_mode=only_full_group_by被限制了,导致以往MySQL版本中能正常查询的sql,不能用了,就是在使用group by的时候select 查询字段一定都要在group by后面的列中,如果select的某些列没在后面,就会报这个错
3.解决方法
1.修改MySQL的配置
通过查询语句查看当前的sql_mode
select @@GLOBAL sql_mode;
或
select @@SESSION sql_mode;
查询结果应该是
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
然后重新设置sql_mode
SET SESSION sql_mode= "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
将ONLY_FULL_GROUP_BY 去掉
2.使用any_value
在查询的列当中使用any_value包裹,group by后的字段不需要使用any_value。
SELECT name, any_value(contact) as contact FROM customer GROUP BY `name`
注意:group by后面的having语句中的字段也需要使用any_value包裹,排序字段亦是如此
4.sql_mode
前面看了关于sql_mode问题,下面深入的了解一下sql_mode到底是什么。
1.什么是sql_mode
sql_mode是一组mysql语法校验规则,定义了mysql应该支持的sql语法、数据校验等
2.sql_mode有什么作用
sql_mode常用来解决下面几个问题
- 通过设置sql_mode,可以完成不同严格程度的数据校验,有效的保障数据准备性。
- 通过设置sql_mode为宽松模式,来保证大多数sql符合标准的语法,这样应用在不同数据库之间进行迁移时,则不需要对业务sql进行较大的修改
- 在不同数据库之间进行数据迁移之前,通过设置sql_mode可以使mysql上的数据更方便的迁移到目标数据库中。
3.如何查看sql_mode配置
查询sqlmode前文已经介绍
select @@GLOBAL sql_mode;
或
select @@SESSION sql_mode;
4.sql_mode模式
sql_mode值 | 描述 |
---|---|
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 | 将“||”作为字符串的链接字符操作,而不是作为运算符,样本“concat”相类似 |
ANSI_QUOTES | 启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符 |