【问题标题】:MySQL INSERT INTO SELECT not matching records are triggered by function str_to_dateMySQL INSERT INTO SELECT 不匹配记录由函数 str_to_date 触发
【发布时间】:2020-06-15 12:07:44
【问题描述】:

我的 MySQL INSERT SELECT 有一个奇怪的行为,我需要将 dt_int 从 TABLE2 转换为 TABLE1 中的日期时间 dt。

表结构是

TABLE1
PK INT(11) -- auto increment
dt datetime

TABLE2
PK INT(11)  -- auto increment
dt_int INT(11)

我有这样的插入选择查询

INSERT INTO TABLE1(dt)
(
  SELECT str_to_date(dt_int, '%Y%m%d')
  FROM TABLE2 
  WHERE str_to_date(dt_int, '%Y%m%d') IS NOT NULL
)

如果表中的所有日期都有效,则可以正常工作。但是,如果表包含类似这样的数据

TABLE2
PK   |   dt_int
1        20201209
2        20202020

它会遇到错误代码 1411: Incorrect datetime value '20202020' for function str_to_date。

内部选择语句仅返回有效日期,但插入语句仍会尝试为过滤的日期转换日期。为什么会这样?有什么我可以做的吗?

[已编辑] MySQL 版本是 5.7,引擎是 InnoDB。目前托管在 Windows 环境中。

【问题讨论】:

  • 您使用的 MySQL 版本和操作系统
  • MySQL版本为5.7
  • 我可以重现你的问题,但我不知道为什么会出现这个问题(在 5.7 和 8.0 中)
  • 类似的事情发生在 MariaDB 10.3
  • @akina 这不是真正的问题 - 如果您自己运行选择,则仅返回 1 条记录并且不报告错误,如果您在插入中运行选择,则会发生错误。跨度>

标签: mysql insert-select str-to-date


【解决方案1】:
INSERT INTO table1
SELECT PK, CONCAT(dt_int DIV 10000, '-1-1') 
           + INTERVAL dt_int MOD 10000 DIV 100 - 1 MONTH 
           + INTERVAL dt_int MOD 100 - 1 DAY
FROM table2
WHERE 0 + DATE_FORMAT(CONCAT(dt_int DIV 10000, '-1-1') 
                      + INTERVAL dt_int MOD 10000 DIV 100 - 1 MONTH  
                      + INTERVAL dt_int MOD 100 - 1 DAY, '%Y%m%d') = dt_int;

fiddle

【讨论】:

  • 为什么 WHERE 中需要 0 +?
  • @SomeoneWhoCodes 这是到数值数据类型的显式转换。似乎它可能会被跳过......但我不喜欢隐式数据类型转换和他们可能带给我的惊喜。
【解决方案2】:

您可以像这样设置/取消设置 SLQ_MODE。然后它工作

SELECT REPLACE(@@SQL_MODE, ',', '\n');

SET @@SQL_MODE = REPLACE(@@SQL_MODE, ',STRICT_TRANS_TABLES', '');

INSERT INTO table2(dt) SELECT * FROM (
SELECT DATE(str_to_date( dt_int , '%Y%m%d')) 
FROM table1
WHERE date(str_to_date( dt_int, '%Y%m%d')) is not null
) as x;

另见SQL_MODE

示例

创建表格

mysql> CREATE TABLE `table1` (
    ->   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    ->   `dt_int` int(11) DEFAULT NULL,
    ->   PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO `table1` (`id`, `dt_int`)
    -> VALUES
    ->     (1, 20200202),
    ->     (2, 20202020);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> CREATE TABLE `table2` (
    ->   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    ->   `dt` date DEFAULT NULL,
    ->   PRIMARY KEY (`id`)
    -> ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.06 sec)

显示数据

mysql> SELECT DATE(str_to_date( dt_int , '%Y%m%d'))
    -> FROM table1
    -> WHERE date(str_to_date( dt_int, '%Y%m%d')) is not null;
+---------------------------------------+
| DATE(str_to_date( dt_int , '%Y%m%d')) |
+---------------------------------------+
| 2020-02-02                            |
+---------------------------------------+
1 row in set, 2 warnings (0.00 sec)

运行错误的查询

mysql> INSERT INTO table2(dt)
    -> SELECT DATE(str_to_date( dt_int , '%Y%m%d'))
    -> FROM table1
    -> WHERE date(str_to_date( dt_int, '%Y%m%d')) is not null;
ERROR 1411 (HY000): Incorrect datetime value: '20202020' for function str_to_date
mysql>

获取 SQL_MODE 并将其删除

mysql>
mysql> SELECT REPLACE(@@SQL_MODE, ',', '\n');
+-------------------------------------------------------------------------------------------------------------------------------------------+
| REPLACE(@@SQL_MODE, ',', '\n')                                                                                                            |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY
STRICT_TRANS_TABLES
NO_ZERO_IN_DATE
NO_ZERO_DATE
ERROR_FOR_DIVISION_BY_ZERO
NO_AUTO_CREATE_USER
NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SET @@SQL_MODE = REPLACE(@@SQL_MODE, ',STRICT_TRANS_TABLES', '');
Query OK, 0 rows affected, 1 warning (0.00 sec)

运行查询没有错误

mysql> INSERT INTO table2(dt) SELECT * FROM (
    -> SELECT DATE(str_to_date( dt_int , '%Y%m%d'))
    -> FROM table1
    -> WHERE date(str_to_date( dt_int, '%Y%m%d')) is not null
    -> ) as x;
Query OK, 1 row affected, 2 warnings (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 2

mysql>

【讨论】:

  • @SomeoneWhoCodes - 我有一个答案给你
猜你喜欢
  • 2016-08-12
  • 2012-08-25
  • 1970-01-01
  • 2017-11-25
  • 1970-01-01
  • 2010-12-19
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多