-
'0000-00-00'日期可以存入MySQL吗
- 网站名称:'0000-00-00'日期可以存入MySQL吗
- 网站分类:技术文章
- 收录时间:2025-06-08 15:52
- 网站地址:
“'0000-00-00'日期可以存入MySQL吗” 网站介绍
前言:
前面文章我们介绍过日期和时间字段的查询方法,最近遇到日期值为零的问题。原来了解过和 sql_mode 参数设置有关,但还不是特别清楚,本篇文章将探究下MySQL怎么处理日期值为零的问题。
1.问题描述
这里我们说的日期为零值是指年、月、日为零,即'0000-00-00'。显然,这是不合法的日期值,但由于设计问题或历史遗留问题,有时候数据库中有类似日期值为零的数据,默认情况下插入零值日期会报错,可以通过修改参数sql_mode模式来避免该问题。下面展示下默认情况下插入零值的情况:
# 首先创建测试表
CREATE TABLE `t_zerodate` (
`increment_id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`year_col` year DEFAULT NULL COMMENT '年',
`date_col` date DEFAULT NULL COMMENT '日期',
`dt_col` datetime DEFAULT NULL COMMENT 'datetime时间',
`ts_col` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'timestamp时间',
PRIMARY KEY (`increment_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='zerodate';
# 查看sql_mode模式
mysql> select @@sql_mode;
+----------------------------------------------------------------------------------------------------+
| @@sql_mode |
+----------------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------------------------------------------+
# 分别插入年、月、日为零值测试
# 年份为0000 插入成功
mysql> insert into t_zerodate (year_col) values (0000);
Query OK, 1 row affected (0.02 sec)
# 月、日都不为零时 可插入成功
mysql> insert into t_zerodate (date_col) values ('0000-00-00');
ERROR 1292 (22007): Incorrect date value: '0000-00-00' for column 'date_col' at row 1
mysql> insert into t_zerodate (date_col) values ('0000-01-00');
ERROR 1292 (22007): Incorrect date value: '0000-01-00' for column 'date_col' at row 1
mysql> insert into t_zerodate (date_col) values ('0000-00-01');
ERROR 1292 (22007): Incorrect date value: '0000-00-01' for column 'date_col' at row 1
mysql> insert into t_zerodate (date_col) values ('0000-01-01');
Query OK, 1 row affected (0.02 sec)
2.sql_mode变更测试
关于sql_mode,原来写过一篇文章,sql_mode支持多个变量的不同组合,不同的sql_mode影响服务端支持的SQL语法以及数据校验规则。其中 NO_ZERO_IN_DATE、NO_ZERO_DATE这两个变量影响MySQL对日期零值的处理。上面测试中可以发现,严格模式下,当sql_mode中包含NO_ZERO_IN_DATE,NO_ZERO_DATE两个变量时,月和日都不为零时可以插入成功。
乍一看,NO_ZERO_IN_DATE和NO_ZERO_DATE两个变量很相似,但作用有什么不同呢?下面我们给出这两个变量的作用并做下具体测试。
NO_ZERO_DATE模式影响服务端是否允许将 '0000-00-00' 作为有效日期。其效果还取决于sql_mode是否启用了严格模式。
- 如果未启用此模式,'0000-00-00'则允许插入并且不会产生警告。
- 如果只启用此模式,'0000-00-00'则允许插入但是会产生警告。
- 如果启用了此模式和严格模式,'0000-00-00'则会被认定为非法,并且插入也会产生错误。除非同时带有IGNORE,对于 INSERT IGNORE和UPDATE IGNORE,'0000-00-00'则允许插入但是会产生警告。
NO_ZERO_IN_DATE模式影响服务端是否允许插入年份部分非零但月或日部分为0的日期。(例如'2010-00-01'或 '2010-01-00',但不影响日期'0000-00-00'),其效果同样还取决于sql_mode是否启用了严格模式。
- 如果未启用此模式,则允许部分为零的日期插入,并且不会产生任何警告。
- 如果只启用此模式,则将该零值日期插入为'0000-00-00'并产生警告。
- 如果启用了此模式和严格模式,则除非IGNORE同时指定,否则不允许插入为零的日期。对于INSERT IGNORE和 UPDATE IGNORE,将该零值日期插入为'0000-00-00'并产生警告。
同时,官方文档中指出:NO_ZERO_DATE和NO_ZERO_IN_DATE虽然不是严格模式的一部分,但应与严格模式结合使用,如果在未启用严格模式的情况下启用了NO_ZERO_DATE或NO_ZERO_IN_DATE则会产生警告,反之亦然,(sql_mode中包含STRICT_TRANS_TABLES,一般可认为启用了严格模式)。
下面我们来测试下,严格模式下分别启用和不启用这两个变量的效果:
1.严格模式下 同时启用NO_ZERO_DATE、NO_ZERO_IN_DATE
# 上文已经测试过,正常情况下 月、日都不为零时 可插入成功
# 下面测试insert ignore into
mysql> set session sql_mode = "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)
mysql> truncate table t_zerodate;
Query OK, 0 rows affected (0.07 sec)
mysql> insert ignore into t_zerodate (date_col) values ('0000-00-00');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> insert ignore into t_zerodate (date_col) values ('2010-00-00');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> insert ignore into t_zerodate (date_col) values ('2010-01-00');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> insert ignore into t_zerodate (date_col) values ('2010-00-01');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select date_col from t_zerodate;
+------------+
| date_col |
+------------+
| 0000-00-00 |
| 0000-00-00 |
| 0000-00-00 |
| 0000-00-00 |
+------------+
# 结论:
正常情况下 月、日都不为零时 可插入成功;
对于INSERT IGNORE则允许插入,但会产生告警,并会将零值日期保存为'0000-00-00'。
2.严格模式下 不启用NO_ZERO_DATE
mysql> set session sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION";
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> truncate table t_zerodate;
Query OK, 0 rows affected (0.08 sec)
mysql> insert into t_zerodate (date_col) values ('0000-00-00');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t_zerodate (date_col) values ('2010-00-01');
ERROR 1292 (22007): Incorrect date value: '2010-00-01' for column 'date_col' at row 1
mysql> insert into t_zerodate (date_col) values ('2010-01-00');
ERROR 1292 (22007): Incorrect date value: '2010-01-00' for column 'date_col' at row 1
mysql> insert into t_zerodate (date_col) values ('0000-00-01');
ERROR 1292 (22007): Incorrect date value: '0000-00-01' for column 'date_col' at row 1
mysql> insert into t_zerodate (date_col) values ('0000-01-00');
ERROR 1292 (22007): Incorrect date value: '0000-01-00' for column 'date_col' at row 1
# 结论:
'0000-00-00'可以正常插入,其余月、日为零的日期插入会报错;
对于INSERT IGNORE则允许插入,但会产生告警,并会将零值日期保存为'0000-00-00'。
3.严格模式下 不启用NO_ZERO_IN_DATE
mysql> set session sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION";
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> truncate table t_zerodate;
Query OK, 0 rows affected (0.07 sec)
mysql> insert into t_zerodate (date_col) values ('0000-00-00');
ERROR 1292 (22007): Incorrect date value: '0000-00-00' for column 'date_col' at row 1
mysql> insert into t_zerodate (date_col) values ('2010-00-00');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t_zerodate (date_col) values ('2010-00-01');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t_zerodate (date_col) values ('2010-01-00');
Query OK, 1 row affected (0.00 sec)
mysql> insert ignore into t_zerodate (date_col) values ('0000-00-00');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select date_col from t_zerodate;
+------------+
| date_col |
+------------+
| 2010-00-00 |
| 2010-00-01 |
| 2010-01-00 |
| 0000-00-00 |
+------------+
# 结论:
'0000-00-00'插入报错,其余月、日为零的日期可以正常插入;
对于INSERT IGNORE则允许插入'0000-00-00',但会产生告警。
4.严格模式下 NO_ZERO_DATE和NO_ZERO_IN_DATE都不启用
mysql> set session sql_mode = "STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION";
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> truncate table t_zerodate;
Query OK, 0 rows affected (0.09 sec)
mysql> insert into t_zerodate (date_col) values ('0000-00-00');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t_zerodate (date_col) values ('2010-00-00');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t_zerodate (date_col) values ('2010-00-01');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t_zerodate (date_col) values ('2010-01-00');
Query OK, 1 row affected (0.01 sec)
# 结论:
'0000-00-00'和其余月、日为零的日期都可以正常插入。
3.结论及建议
简单总结下,NO_ZERO_DATE模式影响'0000-00-00'日期的插入,NO_ZERO_IN_DATE模式影响除'0000-00-00'外的月、日为零的日期的插入。另外无论何种模式,YEAR类型都允许0000插入,这两个变量影响的是DATE、DATETIME、TIMESTAMP三种字段类型中对日期部分为零的处理。
至于我们是否要启用这两种模式,这取决于业务需求。如果你的业务有插入零值日期的需求,则可以选择sql_mode中不要包含NO_ZERO_DATE和NO_ZERO_IN_DATE,例如,某字段要求设置为DATE类型且不为空,默认值设为'0000-00-00'。一般情况下,NO_ZERO_DATE和NO_ZERO_IN_DATE建议同时有或者同时没有,有插入零日期值的需求则可以去除二者,没有此类需要则可以保留二者。这里提醒下,官方文档中讲到,这两个变量在未来版本中不再作为独立变量使用,故官方不推荐使用。
总结:
写了这么多,不知道你认真看了多少,其实本篇文章讲的东西还是比较简单的。如果你遇到过此类问题,再看下本篇文章可能理解会更深刻些,没遇过此类问题的小伙伴,希望这篇文章可以让你知道MySQL对于零值日期有不同的处理。
- 上一篇:了解SQL吗
- 下一篇:PGSQL提取本月跨越的周数及每周的开始结束日期
更多相关网站
- 云服务器:SQL数据库超时的原因与解决方法
- 一个时间戳精度问题,引发了一个MySQL血案
- (二十二) 程序员必备: 10秒到0.1秒,亿级数据下MySQL慢查询分析教程
- MySQL各种SQL的执行频率
- PGSQL提取本月跨越的周数及每周的开始结束日期
- 【SQL】SQL 语法差异大全(PgSQL/MySQL/Oracle/TiDB/OceanBase)
- 了解SQL吗
- SQL用了两年多,分享2个最常用的小技巧
- 从Sql角度,对比学习Python数据处理包pandas
- SqlServer根据身份证号码查询出生日期和年龄
- 吊打面试官(十一)--Java语言中日期处理相关问题总结
- 玩转MySQL的时间类型:Date、DateTime、TimeStamp、Time
- 多表关联查询的性能优化技巧:预关联
- SQL学习:SQL同比分析案例讲解,一看就懂
- java.util.Date、java.sql.Date、java.sql.Timestamp区别和总结
- 疯传!Java 日期时间底层逻辑大揭秘,看完直接拿捏面试官挖的坑!
- 记一次有意思的 SQL 实现 → 分组后取每组的第一条记录
- 全量跑1小时 vs 增量抽1分钟!选对时间戳&主键增量的ETL方法更省时
- 最近发表
-
- JavaScript,ES6,数值扩展,二进制、八进制和十六进制,方法
- 如何用2 KB代码实现3D赛车游戏?2kPlus Jam大赛了解一下
- 10个JavaScript一行代码,解决90%的开发难题
- 如何使用 Fraction.js 解决 BigInt 的计算盲区?
- js四舍五入(js中四舍五入的代码怎么打)
- 全能硬件大师AIDA64 v4.60 最新绿色版下载
- 实用神帖 隔壁老王买到iPhone 6魔改6s,怎么破?
- DIY装机小白的618配机历程(3千元的146K,DDR5无卡方案)2025
- AIDA64 7.30版本发布:改善深色/高对比度模式
- DIY从入门到放弃:CPU没有SN码是保护你
- 标签列表
-
- mydisktest_v298 (35)
- sql 日期比较 (33)
- document.appendchild (35)
- 头像打包下载 (35)
- 二调符号库 (23)
- acmecadconverter_8.52绿色版 (25)
- 梦幻诛仙表情包 (36)
- 魔兽模型 (23)
- java面试宝典2019pdf (26)
- disk++ (30)
- 加密与解密第四版pdf (29)
- iteye (26)
- parsevideo (22)
- centos7.4下载 (32)
- cuda10.1下载 (22)
- intouch2014r2sp1永久授权 (33)
- usb2.0-serial驱动下载 (24)
- jdk1.8.0_191下载 (27)
- axure9注册码 (30)
- virtualdrivemaster (26)
- 数据结构c语言版严蔚敏pdf (25)
- 兔兔工程量计算软件下载 (27)
- 代码整洁之道 pdf (26)
- ccproxy破解版 (31)
- aida64模板 (28)