MySQL5.7中的sql_mode默认值
简介
在正常项目开发过程中,如果MySQL版本从5.6升级到5.7版本。作为DBA在考虑数据库版本升级带来的影响时,一般会有几个注意点:
sql_mode默认值的改变optimizer_switch值的改变- 备库升级影响主备复制
本文主要内容是MySQL升级到5.7版本之后,由于默认的sql_mode值带来的坑以及对应的解决方案。
案例一:ONLY_FULL_GROUP_BY
问题描述
MySQL版本从5.6升级至5.7之后,部分SQL执行报错,报错信息如下:
1
ERROR 1055 (42000): Expression #3 of XXXXXX list is not in GROUP BY clause and contains nonaggregated column ‘XXXXX.XXXXXX’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
这个问题原因在于从5.6升级至5.7版本后 sql_mode 默认值发生了改变,在5.7版本的 sql_mode 默认值中有意向 ONLY_FULL_GROUP_BY,该选项的含义表示:对于使用 GROUP BY 进行查询的SQL,不允许 SELECT 部分出现 GROUP BY 中未出现的字段,也就是 SELECT 查询的字段必须是 GROUP BY 中出现的或者使用聚合函数的或者是具有唯一属性的。
解决方案
- 方案一(不推荐):修改5.7版本
sql_mode值,将ONLY_FULL_GROUP_BY去掉ONLY_FULL_GROUP_BY是加强SQL规范的,其目的是让SQL查询出来的结果更符合规范,更准确。
如果没有ONLY_FULL_GROUP_BY规范限制,那么则能允许以下SQL的执行:SELECT a,b,c FROM t GROUP BY a。SQL按照a字段值进行分组,当同一个a字段值对应多个b或者c值时,查询结果中的b,c值是不确定的。 - 方案二:对于不符合
ONLY_FULL_GROUP_BY限制的字段,添加unique索引 - 方案三:改写SQL,按照规范编写SQL
- 方案四:使用ANY_VALUE(),对于不符合
ONLY_FULL_GROUP_BY的字段使用ANY_VALUE()函数,让MySQL跳过ONLY_FULL_GROUP_BY检测
1
2
3
4
5
6mysql> SELECT name, address, MAX(age) FROM t GROUP BY name;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP
BY clause and contains nonaggregated column 'mydb.t.address' which
is not functionally dependent on columns in GROUP BY clause; this
is incompatible with sql_mode=only_full_group_by
mysql>SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;
案例二:NO_ZERO_DATE & NO_ZERO_IN_DATE & time_zone
问题描述
排错阶段一
MySQL版本从5.6升级至5.7之后,创建表的过程中失败:
1 |
mysql> CREATE TABLE `t_manager` ( |
错误提示 MODIFY_DATETIME 字段设置的默认值是无效的,考虑到刚从5.6版本升级到5.7版本,于是又去翻了翻5.7中默认的 sql_mode 值。结果发现了两个可能存在影响的选项:
NO_ZERO_DATE:MySQL中插入的时间字段值,不允许日期为零NO_ZERO_IN_DATE:MySQL中插入的时间字段值,不允许日期和月份为零
排错阶段二
于是解决方案就是按照
NO_ZERO_DATE以及NO_ZERO_IN_DATE的要求设置默认值,将MODIFY_DATETIME字段默认值设置为’1001-01-01 01:01:01’,结果发现还是无法成功创建表:1
2
3
4
5
6
7
8
9
10mysql>CREATE TABLE `t_manager` (
.....
-> `CREATE_DATETIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-> `MODIFIER` varchar(32) DEFAULT NULL COMMENT '更新人',
-> `MODIFY_DATETIME` timestamp NOT NULL DEFAULT '1001-01-01 01:01:01' ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
-> `IS_DELETED` bit(1) DEFAULT b'0' COMMENT '删除状态 1:删除 0:未删除',
-> `IS_ENABLE` bit(1) DEFAULT b'1' COMMENT '启用状态 1:启用 0:禁用',
-> PRIMARY KEY (`CACHE_ID`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ERROR 1067 (42000): Invalid default value for 'MODIFY_DATETIME'
查看了所有的 sql_mode 值,都符合规范,但是表还是创建不成功。只好去官方手册上找找timestamp介绍:
The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of ‘1970-01-01 00:00:01’ UTC to ‘2038-01-19 03:14:07’ UTC.
排错阶段三
可以看到官方定义中timestamp字段值的范围是’1970-01-01 00:00:01’到’2038-01-19 03:14:07’,原来是我们设置的默认值不在timestamp范围之内。于是再次修改默认值:
1 |
mysql>CREATE TABLE `t_manager` ( |
邪了门,居然还是无法成功创建表。实在是没辙了,向同事求救,同事说他在机器上试试,结果同样的语句在他的MySQL上执行成功,同样是5.7.23版本。
百思不得其解。
一气之下将两边的参数值拿出来对比了一下,果然找到了不同的根本。
| 测试环境 | 同事环境 |
|---|---|
| system_time_zone=CST | system_time_zone UTC |
| time_zone=’+08:00’ | time_zone=SYSTEM |
回过头来看timestamp字段定义的范围:
The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of ‘1970-01-01 00:00:01’ UTC to ‘2038-01-19 03:14:07’ UTC.
这个时间范围指的是UTC时区的时间范围,测试环境设置了CST东八区的时区,则对应的时间范围上也需要对应的加8小时。所以将timestamp字段默认值修改为’1970-01-01 08:00:01’,表终于创建成功。
1 |
mysql>CREATE TABLE `mn_cache_refresh_manager` ( |
解决方案
- 将timestamp字段默认值修改为对应CST时区的最小值’1970-01-01 08:00:01’
总结
最后总结一下MySQL中5.7中sql_mode参数默认值的几个意思
- ONLY_FULL_GROUP_BY
对于使用GROUP BY进行查询的SQL,不允许SELECT部分出现GROUP BY中未出现的字段,也就是SELECT查询的字段必须是GROUP BY中出现的或者使用聚合函数的或者是具有唯一属性的。 - STRICT_TRANS_TABLES
该选项针对事务性存储引擎生效,对于非事务性存储引擎无效,该选项表示开启strict sql模式。在strict sql模式下,在INSERT或者UPDATE语句中,插入或者更新了某个不符合规定的字段值,则会直接报错中断操作 - NO_ZERO_IN_DATE
MySQL中插入的时间字段值,不允许日期和月份为零 - NO_ZERO_DATE
MySQL中插入的时间字段值,不允许日期为零 - ERROR_FOR_DIVISION_BY_ZERO
INSERT或者UPDATE语句中,如果数据被0除,则出现警告(非strict sql模式下)或者错误(strict sql模式下)。- 当该选项关闭时,数字被0除,得到NULL且不会产生警告
- 当该选项开启且处于非strict sql模式下,数字被0除,得到NULL但是会产生警告
- 当该选项开启且处于strict sql模式下,数字被0除,产生错误且中断操作
- NO_AUTO_CREATE_USER
之前版本中使用GRANT语法,如果用户不存在则会自动创建用户,该选项限制该功能 - NO_ENGINE_SUBSTITUTION
在使用CREATE TABLE或者ALTER TABLE语法执行存储引擎的时候,如果设定的存储引擎被禁用或者未编译,会产生错误。
MySQL5.7中的sql_mode默认值的更多相关文章
- struts2视频学习笔记 03-06(Struts 2配置文件无提示问题,Action配置中的各项默认值,各种转发类型)
课时3 解决Struts 2配置文件无提示问题(eclipse):window→preference→XML→XML Catlog
- sqlserver中GUID的默认值设置
sqlserver中GUID的默认值设置 YID uniqueidentifier not null default (NEWSEQUENTIALID()), //有序GUID(只能用于表设计的时候的 ...
- c++ 中bool 的默认值
比如在Test.h中定义变量: _isFirst; //Test.h头文件 #ifndef __TEST_H__ #define __TEST_H__ class Test{ private: boo ...
- 弹窗中修改select默认值遇到的问题
弹窗中修改select默认值无效 前提: 项目中遇到一个需求, 在一个弹窗中,有很多个select都是在打开弹窗的同时由js自动生成的(每次打开都自动重新生成一遍). 弹窗打开后,从每个select的 ...
- @RequestMapping中method的默认值是什么?
@RequestMapping中method的默认值是什么? 没有默认值,如果不配置method, 则以任何请求形式 RequestMethod.GET, RequestMethod.POST, Re ...
- PostgreSQL中实现更新默认值(二)
今天我们用表继承+触发器的方案,来实现表中的更新默认值.这也许是PostgreSQL里最佳的解决方案. 一. 创建一张表,作为父表 create table basic_update( t_updat ...
- MySQL5.0+提示字段没有默认值(doesn’t have a default value)的解决方法
方法一: 打开my.ini,查找 sql-mode=”STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION” 修改为 sql ...
- js中function参数默认值
--在dreamweaver做网站时,函数定义是在一个*.js文件中,其中定义了一个func,有四个参数,function func(string1,url,flag,icon),然后在另一个asp中 ...
- es6中参数【默认值,扩展运算符】
参数默认值 1.普通参数 function info(age,name="grace"){ console.log(name); } info(); //输入:grace 2.对象 ...
随机推荐
- 可能比文档还详细--VueRouter完全指北
可能比文档还详细--VueRouter完全指北 前言 关于标题,应该算不上是标题党,因为内容真的很多很长很全面.主要是在官网的基础上又详细总结,举例了很多东西.确保所有新人都能理解!所以实际上很多东西 ...
- Nginx + Keepalived负载均衡
第一步: 下载keepalived地址:http://www.keepalived.org/download.html 解压安装: tar -zxvf keepalived-1.2.18.tar.gz ...
- c time类型详解
linux下存储时间常见的有两种存储方式,一个是从1970年01月01日 0:00:00到现在经过了多少秒,一个是用一个结构来分别存储年月日时分秒的.time_t 这种类型就是用来存储从1970年到现 ...
- snmp自定义OID与文件下载----服务器端配置
客户端使用命令工具:snmpwalk 服务端开启服务 snmp service.下载安装 net-snmp. 最近做了一些工作,记性较差感觉还是记下来比较好,毕竟网上能查到的有用的资料太少了. 自定义 ...
- 单机多实例mysq 8.0l部署安装
单机多实例mysql部署安装 目的需求 在单台虚拟机部署部署多实例mysql,用于配置mysql replication,MHA等. 思路 多实例安装mysql可以参考<源编译MySQL8.0的 ...
- [转]微擎load()文件加载器
本文转自:https://blog.csdn.net/qq_32737755/article/details/78124534 微擎中加载文件需要用到 load() 在官网找到官方对load()的解释 ...
- SQL SERVER 数据库面试题
1.用一条SQL语句 查询出每门课都大于80分的学生姓名 name kecheng fenshu 张三 语文 81张三 数学 75李四 语文 ...
- 无法初始化 PowerShell 主机解决方案
Question无法初始化 PowerShell 主机.如果您的 PowerShell 执行策略设置设为 AllSigned,请先打开程序包管理器控制台以初始化该主机. --------------- ...
- WINAPI实现简易扫雷游戏
//扫雷 #include <windows.h> #include <windowsx.h> #include <strsafe.h> #include < ...
- Python3.7 数字之间下划线
只是为了提高可读性,数值没变. >>> yes_votes = 42_572_6540 ; >>> yes_votes = 42_572_654099 ; > ...