英文:
mysql8: Incorrect datetime value: '2016-02', what can I do?
问题
例如,有两个表格如下:
- 原始表格
date_str |
---|
2016-02 |
2016-02-02 |
- 新表格(基于原始表格创建,添加了一个日期字段)
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.cnf
的sql_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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论