MYSQL 令人头疼的日期验证

MYSQL date validation head-scratcher

我 运行 遇到了一个问题,试图将日期插入 table 中,我这辈子都弄不明白。假设我这样做:

select "2018-11-40" from dual where dayname("2018-02-31") is not null;

我正确地返回了 0 行,因为 11 月 40 日不是有效日期。

但是如果我有一个带有日期字段 EVENT_DATE 的 table MY_TABLE,然后执行此操作:

insert into MY_TABLE (EVENT_DATE)

select "2018-11-40" from dual where dayname("2018-11-40") is not null;

它出错了:不正确的日期时间值:'2018-11-40',而不是 运行 没有错误和 0 行受影响。

(dayname("2018-11-40") is not null) 绝对应该在插入之前解析为 false ... 如果我这样做:

insert into MY_TABLE (EVENT_DATE)
select "2018-11-40" from dual where 1=2;

一切正常(没有错误。0 行受影响)。

那么是什么原因呢?这是在 MySQL 5.7.21

在 DML 语句 (INSERT/UPDATE/DELETE) 中,1292 是一个错误。

但是在SELECT语句中,1292不是错误。这是一个警告,因此语句可以继续处理。

Query: select '2018-11-40' + INTERVAL 0 DAY

1 row(s) affected, 1 warning(s)

Warning Code : 1292
Incorrect datetime value: '2018-11-40'

SELECT 语句发出警告。 MySQL 报告它,但您的客户端应用忽略了它。

不同之处在于,在 warning 条件下,语句可以继续处理。在 INSERT 语句的上下文中,1292 是一个错误,语句处理停止。

sql_mode 的设置可能会影响 MySQL 5.7 中的此行为,例如,让 SELECT 语句抛出错误而不是警告。)


我们可以看到与错误 1411 相同的行为。这是 DML 中的错误,SELECT 中的警告。

Query: select STR_TO_DATE('2018-11-40','%Y-%m-%d')

1 row(s) affected, 1 warning(s)

Warning Code : 1411
Incorrect datetime value: '2018-11-40' for function str_to_date

使用 mysql 5.7,您对 select "2018-11-40" from dual where dayname("2018-02-31") is not null; 的初始查询实际上会生成警告。

您可以通过直接使用 show warnings;

跟随该查询来看到此警告

您应该会看到与此类似的内容:

+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1292 | Incorrect datetime value: '2018-02-31' |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

如果我理解正确的话,你发现有问题的是你认为从测试 select 到你尝试使用 select 作为输入的行为的变化插入。

这个问题的答案与您可以配置的various server sql mode settings有关。

您看到的是 "strict mode" 与默认设置 NO_ZERO_DATE 的组合。手册对设置组合的说明如下:

If this mode and strict mode are enabled, '0000-00-00' is not permitted and inserts produce an error, unless IGNORE is given as well. For INSERT IGNORE and UPDATE IGNORE, '0000-00-00' is permitted and inserts produce a warning.

您的无效日期将被转换为“00”,当您使用 SELECT 闲逛时,这会触发警告,但如果您随后尝试将其与 INSERT 结合使用,则会引发全面错误。