【问题标题】:Mysql "ERROR 1292 (22007): Truncated incorrect time value: '2355:46:39.000000'" during insertMysql“错误1292(22007):截断不正确的时间值:'2355:46:39.000000'”在插入期间
【发布时间】:2019-08-06 18:29:56
【问题描述】:

我目前正在计算一个日期时间列与另一个日期时间列的滞后变量之间的时间差,该列来自一个较小的表。 然后将结果插入到更大的最终表中。 这是一个过程的一部分,我有几个较小的表作为 csv,对于每个表,必须计算滞后差异并将其加载到最终表中(最终表大约为 20GB,12 个较小的表每个大约为 2.5GB )

我之前已经做了几次没有滞后变量的单独插入,一切都很好。 然而,在 12 的表 6 中,我现在得到以下错误,我不知道为什么:

ERROR 1292 (22007): Truncated incorrect time value: '2355:46:39.000000'

我可以提供一个适用于其余表格的测试示例:

DROP TABLE IF EXISTS single_test;

CREATE TABLE single_test(
medallion VARCHAR(64),
hack_license VARCHAR(64),
pickup_datetime DATETIME,
dropoff_datetime DATETIME,
id  INT NOT NULL,
PRIMARY KEY (id) 
);
INSERT INTO single_test VALUES
('a', '1' , '2013-01-06 00:18:35','2013-01-06 02:10:33',1),
('a', '1' , '2013-01-06 02:40:58','2013-01-06 03:40:01',2),
('b', '1' , '2013-01-06 04:07:21','2013-01-06 05:00:41',3),
('c', '1' , '2013-01-07 13:12:08','2013-01-07 13:32:27',4),
('a', '2', '2013-01-06 03:50:30','2013-01-06 04:22:13',5),
('a', '2', '2013-01-06 04:41:23','2013-01-06 04:57:04',6),
('d', '2', '2013-01-07 12:22:56','2013-01-07 13:02:14',7),
('d', '3', '2013-01-07 13:03:24','2013-01-07 15:47:31',8)
;


CREATE TABLE final_test(
medallion VARCHAR(64),
hack_license VARCHAR(64),
pickup_datetime DATETIME,
dropoff_datetime DATETIME,
id  INT NOT NULL,
delta VARCHAR(20),
current_dropoff DATETIME,
current_hack VARCHAR(64),
PRIMARY KEY (id) 
);

SET @quot= '000-00-00 19:19:19';
SET @current_hack = ''; 
INSERT INTO final_test
SELECT medallion, hack_license, pickup_datetime, dropoff_datetime, id,
IF(@current_hack = hack_license,TIMEDIFF(pickup_datetime,  @quot),NULL) as delta,
@quot:= dropoff_datetime current_dropoff, @current_hack:= hack_license
FROM single_test ORDER BY hack_license, pickup_datetime;

结果如下所示:

SELECT * FROM final_test;
+-----------+--------------+---------------------+---------------------+----+-----------------+---------------------+--------------+
| medallion | hack_license | pickup_datetime     | dropoff_datetime    | id | delta           | current_dropoff     | current_hack |
+-----------+--------------+---------------------+---------------------+----+-----------------+---------------------+--------------+
| a         | 1            | 2013-01-06 00:18:35 | 2013-01-06 02:10:33 |  1 | NULL            | 2013-01-06 02:10:33 | 1            |
| a         | 1            | 2013-01-06 02:40:58 | 2013-01-06 03:40:01 |  2 | 00:30:25.000000 | 2013-01-06 03:40:01 | 1            |
| b         | 1            | 2013-01-06 04:07:21 | 2013-01-06 05:00:41 |  3 | 00:27:20.000000 | 2013-01-06 05:00:41 | 1            |
| c         | 1            | 2013-01-07 13:12:08 | 2013-01-07 13:32:27 |  4 | 32:11:27.000000 | 2013-01-07 13:32:27 | 1            |
| a         | 2            | 2013-01-06 03:50:30 | 2013-01-06 04:22:13 |  5 | NULL            | 2013-01-06 04:22:13 | 2            |
| a         | 2            | 2013-01-06 04:41:23 | 2013-01-06 04:57:04 |  6 | 00:19:10.000000 | 2013-01-06 04:57:04 | 2            |
| d         | 2            | 2013-01-07 12:22:56 | 2013-01-07 13:02:14 |  7 | 31:25:52.000000 | 2013-01-07 13:02:14 | 2            |
| d         | 3            | 2013-01-07 13:03:24 | 2013-01-07 15:47:31 |  8 | NULL            | 2013-01-07 15:47:31 | 3            |
+-----------+--------------+---------------------+---------------------+----+-----------------+---------------------+--------------+
8 rows in set (0,00 sec)

相比之下,错误消息没有多大意义,因为我希望 TIMEDIFF 截断任何无效输入:

# Extremely Large difference
SELECT TIMEDIFF("2013-01-01 19:00:00","1900-01-01 19:00:00");
+-------------------------------------------------------+
| TIMEDIFF("2013-01-01 19:00:00","1900-01-01 19:00:00") |
+-------------------------------------------------------+
| 838:59:59                                             |
+-------------------------------------------------------+
1 row in set, 1 warning (0,00 sec)

# Invalid/ unrealistic datetime format due to to high/ to low values
SELECT TIMEDIFF("2013-01-01 19:00:00","000-00-00 19:19:19");
+------------------------------------------------------+
| TIMEDIFF("2013-01-01 19:00:00","000-00-00 19:19:19") |
+------------------------------------------------------+
| 838:59:59                                            |
+------------------------------------------------------+
1 row in set, 1 warning (0,00 sec)

# Invalid/ unrealistic datetime format due to character in values
SELECT TIMEDIFF("2013-01-01 19:00:00","000-00-00T 19:19:19");
+-------------------------------------------------------+
| TIMEDIFF("2013-01-01 19:00:00","000-00-00T 19:19:19") |
+-------------------------------------------------------+
| NULL                                                  |
+-------------------------------------------------------+
1 row in set, 1 warning (0,00 sec)

我正在使用 Mysql 5.7。

我还在较小的数据中搜索了字母表中的无效字符,但一无所获。

最好的问候

PS:我知道这个 SO 线程,但它没有提供任何帮助 Error Code: 1292. Truncated incorrect time value

【问题讨论】:

  • 如何重现该问题?您的代码works on db-fiddle。请发布select @@sql_mode;的结果
  • 这是一个更简短的可重现示例:db-fiddle.com/f/6UP4Za8wvaVB9JcTCS6F4t/0
  • 恕我直言,这个错误是有道理的。对我来说没有意义的是它是在插入语句上抛出的,而不是在选择语句上。
  • 太棒了!这也是我的问题:为什么我会收到一个错误,它会中断我的插入查询而不是截断值。您的回答并没有解决问题,而是缩小了问题范围并提供了一个可重复的示例!也许您或我应该根据您在另一个线程中的小提琴发布更精确的问题
  • select @@sql_mode; 的结果@ ` | @@sql_mode | 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 | `

标签: mysql datetime


【解决方案1】:

可以使用以下脚本重现该问题:

create table test(
  tdiff varchar(20)
);

set @dt1 = '1900-01-01 19:00:00';
set @dt2 = '2013-01-01 19:00:00';

select TIMEDIFF(@dt2, @dt1);

insert into test (tdiff) select TIMEDIFF(@dt2, @dt1);

虽然 SELECT 语句返回 838:59:59,但具有相同表达式的 INSERT 语句会引发错误:

错误:ER_TRUNCATED_WRONG_VALUE:截断不正确的时间值: '990552:00:00'

类似的查询也会遇到类似的问题

insert into test (tdiff) select cast('abc' as char(2));

insert into test (tdiff) select '9999-12-31' + interval 1 day;

而相应的 SELECT 语句将返回 abNULL 而不会出错。

错误的原因是STRICT_TRANS_TABLES 模式。如果这种行为有意义,我们可以争论 - 但我怀疑它会改变。

那你能做什么?

1。使用 INSERT IGNORE ..

insert ignore into test (tdiff) select TIMEDIFF(@dt2, @dt1);

INSERT 之后使用IGNORE 会将这些错误转换为警告。这似乎是最简单的方法。

2。禁用 STRICT_TRANS_TABLES 模式

您可以仅针对一个语句禁用STRICT_TRANS_TABLES 模式:

set @old_sql_mode = @@sql_mode;
set session sql_mode = replace(@@sql_mode, 'STRICT_TRANS_TABLES', '');

<your INSERT statement here>;

set session sql_mode = @old_sql_mode;

3。使用条件表达式

由于有效范围是从-838:59:59+838:59:59,我们可以检查小时的绝对差是否小于839 - 否则返回一些其他值:

insert into test (tdiff) select 
  case when abs(timestampdiff(hour, @dt2, @dt1)) < 839
    then TIMEDIFF(@dt2, @dt1)
    else 'out of range'
  end

4。节省秒数而不是时间

这将是我的首选解决方案。使用TIMESTAMPDIFF() 以秒为单位获取差异:

insert into test (tdiff) select timestampdiff(second, @dt1, @dt2);

请注意,TIMESTAMPDIFF() 使用的参数顺序与 TIMEDIFF() 不同。因此,如果您想获得肯定的结果,则应首先出现最小的 DATETIME 值。

【讨论】:

  • 哇!多么惊人的答案!我想我从您的每个解决方案中都学到了一些新东西!非常感谢
【解决方案2】:

来自官方 MySQL 文档:

DATETIME 类型用于同时包含日期和时间的值 部分。 MySQL 检索并显示 'YYYY-MM-DD 中的 DATETIME 值 hh:mm:ss' 格式。支持的范围是 '1000-01-01 00:00:00' 到 '9999-12-31 23:59:59'。

2355:46:39.00000 明显超出了 00:00:00 - 23:59:59 的支持范围。

| TIMEDIFF("2013-01-01 19:00:00","1900-01-01 19:00:00") |
+-------------------------------------------------------+
| 838:59:59  

如果您对此查询的预期结果是 00:00:00,而不是 838:59:59,请尝试以下操作:

TIMEDIFF(TIME("2013-01-01 19:00:00"),TIME("1900-01-01 19:00:00"));

来源:https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time

【讨论】:

  • 这段代码抛出了一个语法错误``` TIMEDIFF(TIME("2013-01-01 19:00:00"),TIME("1900-01-01 19:00:00") ); ``` 我也明白 2355:46:39.00000 超出了范围。问题是为什么我得到一个错误来停止我的整个 INSERT 语句,而不是像你的示例中那样截断值``` | TIMEDIFF("2013-01-01 19:00:00","1900-01-01 19:00:00") | +-------------------------------------------------- ------+ | 838:59:59 ``` 将是完美的
  • 好的,我登录到我的 MySQL droplet 并 SELECT TIMEDIFF(TIME("2013-01-01 19:00:00"),TIME("1900-01-01 19:00:00" ));按预期在 0.0004 秒内返回 00:00:00。看到这个小提琴:db-fiddle.com/f/6UP4Za8wvaVB9JcTCS6F4t/6 如果你继续使用其他 MySQL 函数截断“2355:46:39.00000”中的尾随零,它仍然会在数字上超出数据类型的范围。
猜你喜欢
  • 2023-02-25
  • 2020-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
  • 2017-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多