mysql8: 日期时间值不正确:’2016-02’,我该怎么办?

huangapple go评论78阅读模式
英文:

mysql8: Incorrect datetime value: '2016-02', what can I do?

问题

例如,有两个表格如下:

  1. 原始表格
date_str
2016-02
2016-02-02
  1. 新表格(基于原始表格创建,添加了一个日期字段)
date_str is_date
2016-02
2016-02-02

原始表格中的 date_str 应该是日期格式,但实际字段类型是 varchar,并且存储的数据多种多样,不仅包括日期格式字符串,还包括其他格式(例如,123、abc等)。

我现在要从原始表格中提取 date_str 字段并插入到新表格中。在插入时检查是否为日期格式,如果不是,则在 is_date 字段中填充 DATE_FORMAT

我的SQL语句是:

INSERT INTO new_table ( date_str, is_date ) 
SELECT
ot.date_str  AS date_str,
CASE	
	WHEN DATE_FORMAT( ot.date_str, '%Y-%m-%d' ) IS NULL 
	THEN 'DATE_FORMAT' 
END AS is_date 
FROM original_table ot

如果执行这个SQL,你会得到一个错误:Incorrect DateTime value: '2016-02'

我在互联网上查找了一下,需要调整MySQL配置文件 my.cnf,从配置文件中删除 sql_mode=STRICT_TRANS_TABLES,但我不想这样做,因为会影响其他表格。

英文:

For example, there are two tables like this:

1.original table

date_str
2016-02
2016-02-02

2.new table(Created based on the original table, an additional is date field is added)

date_str is_date
2016-02
2016-02-02

date_str in the original table should be in date format, but the actual field type is varchar, and the data stored is also a variety of, not only date format strings, but also other formats (for example, 123, abc, etc.).
I will now extract the date_str field from the original table and insert it into the new table. Check whether it is in date format when inserting, and if not, fill DATE_FORMAT in the is_date field

My SQL statement is:

INSERT INTO new_table ( date_str, is_date ) 
SELECT
ot.date_str  AS date_str,
CASE	
	WHEN DATE_FORMAT( ot.date_str, '%Y-%m-%d' ) IS NULL 
	THEN 'DATE_FORMAT' 
END AS is_date 
FROM original_table ot

If you execute this SQL, you will get an error: Incorrect DateTime value: '2016-02'

I looked it up on the Internet and needed to adjust the MySQL configuration file my.cnf to remove the sql_mode=STRICT_TRANS_TABLES from the configuration file, but I didn't want to do so, because it would affect other tables.

答案1

得分: 1

使用STR_TO_DATE而不是DATE_FORMAT。该方法将字符串解析为日期,并在无法解析字符串时返回NULL。

SELECT 
    IF(STR_TO_DATE(date_str, '%Y-%m-%d') IS NULL, 1, 0) as is_date
FROM table_name

除SQLite以外的所有数据库中,日期都是二进制值,没有格式。大多数数据库会隐式地将字符串解析为日期。如果解析失败,整个查询都会失败。

DATE_FORMAT本身期望将日期值格式化为字符串。

查询能够工作的唯一原因是MySQL在将字符串传递给DATE_FORMAT之前隐式地将其解析为日期。当隐式转换失败时,整个查询都会失败。在这一点上,DATE_FORMAT还没有被调用。

这个示例,也可以在这个dbFiddle中看到,创建了一个带有一些文本字段和计算is_date字段的表。

CREATE TABLE MyTable(
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    date_str varchar(50),
    is_date boolean null
);
INSERT INTO MyTable(date_str)
VALUES
('2016-02-16'),
('2016-02'),
('Banana');

使用STR_TO_DATE的查询返回以下结果

SELECT ID, IF(STR_TO_DATE(date_str, '%Y-%m-%d') IS NULL, 0, 1) as is_date
FROM MyTable;

------
ID  is_date
1   1
2   0
3   0

要更新表,我们需要使用IGNORE。如果值不匹配,STR_TO_DATE会生成警告。SELECT不关心,但UPDATE/INSERT将警告转换为错误:

UPDATE IGNORE MyTable     
    Set MyTable.is_date=IF(STR_TO_DATE(date_str, '%Y-%m-%d'), 0, 1)
;

SELECT * 
FROM MyTable;
-----

ID  date_str    is_date
1   2016-02-16  0
2   2016-02     1
3   Banana      1
英文:

Use STR_TO_DATE instead of DATE_FORMAT. That method parses strings into dates and returns NULL if the string can't be parsed.

SELECT 
    IF(STR_TO_DATE( date_str, '%Y-%m-%d' ) IS NULL,1,0) as is_date
FROM table_name

Dates in all databases except SQLite are binary values, they have no format. Most databases will parse strings into dates implicitly though. If the parse fails, the entire query fails.

DATE_FORMAT itself expects a date value to format into a string.

The only reason the query works at all is that MySQL implicitly parses the string into a date before passing it to DATE_FORMAT. When the implicit cast fails, the entire query fails. At that point, DATE_FORMAT hasn't been called yet.

This example, also shown in this dbFiddle, creates a table with some text fields and calculates the is_date fields.

CREATE TABLE MyTable(
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    date_str varchar(50),
    is_date boolean null
);
INSERT INTO MyTable(date_str)
VALUES
('2016-02-16'),
('2016-02'),
('Banana');

A query with STR_TO_DATE returns the following result

SELECT ID,IF(STR_TO_DATE(date_str,'%Y-%m-%d') is null,0,1) as is_date
FROM MyTable;

------
ID	is_date
1	1
2	0
3	0

To update the table we need to use IGNORE. STR_TO_DATE generates a warning if the value doesn't match. SELECT doesn't care but UPDATE/INSERT will convert the warning to an error :

UPDATE IGNORE MyTable     
    Set MyTable.is_date=IF(STR_TO_DATE(date_str,'%Y-%m-%d'),0,1)
;

SELECT * 
FROM MyTable;
-----

ID	date_str	is_date
1	2016-02-16	0
2	2016-02	    1
3	Banana	    1

答案2

得分: -1

你可以临时设置mysql配置文件my.cnfsql_model属性,移除STRICT_TRANS_TABLES,然后在执行SQL后再添加回来。以下是SQL:

set sql_mode='ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

INSERT INTO new_table (date_str, is_date) 
SELECT
ot.date_str AS date_str,
CASE    
    WHEN DATE_FORMAT(ot.date_str, '%Y-%m-%d') IS NULL 
    THEN 'DATE_FORMAT' 
END AS is_date 
FROM original_table ot;

set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

或者使用正则表达式。
英文:

You can temporarily set the sql_model attribute of the mysql configuration file my.cnf, remove STRICT_TRANS_TABLES, and then add it back after the sql is executed. The sql is:

set sql_mode='ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

INSERT INTO new_talbe ( date_str, is_date ) 
SELECT
ot.date_str AS date_str,
CASE    
    WHEN DATE_FORMAT( ot.date_str, '%Y-%m-%d' ) IS NULL 
    THEN 'DATE_FORMAT' 
END AS is_date 
FROM original_table ot;

set sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

Or use regular expressions.

huangapple
  • 本文由 发表于 2023年6月8日 16:08:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76429850.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定