代码之家  ›  专栏  ›  技术社区  ›  zombat

mysql str_to_date给出的结果无效?

  •  4
  • zombat  · 技术社区  · 14 年前

    我在Win64上使用MySQL5.1.49。我们在Solaris机器上也看到了以下行为。这是我的测试台:

    CREATE TABLE `date_test` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `date1` datetime NOT NULL,
      PRIMARY KEY (`id`),
      KEY `Index_2` (`date1`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    mysql> select * from date_test;
    +----+---------------------+
    | id | date1               |
    +----+---------------------+
    |  1 | 2010-09-01 01:00:00 |
    |  2 | 2010-09-06 23:59:59 |
    |  3 | 2010-09-07 01:00:00 |
    +----+---------------------+
    3 rows in set (0.00 sec)
    

    以下查询正确运行:

    mysql> SELECT * FROM date_test WHERE
               date1 > DATE_SUB('2010-10-06 23:59:59', interval 1 month);
    +----+---------------------+
    | id | date1               |
    +----+---------------------+
    |  3 | 2010-09-07 01:00:00 |
    +----+---------------------+
    1 row in set (0.00 sec)
    

    但是,如果我投 STR_TO_DATE() 在这里,查询不能按预期工作:

    mysql> SELECT * FROM date_test WHERE
             date1 > DATE_SUB(
                STR_TO_DATE('10/06/2010 23:59:59', '%m/%d/%Y %T'), interval 1 month
             );
    +----+---------------------+
    | id | date1               |
    +----+---------------------+
    |  1 | 2010-09-01 01:00:00 |
    |  2 | 2010-09-06 23:59:59 |
    |  3 | 2010-09-07 01:00:00 |
    +----+---------------------+
    3 rows in set (0.00 sec)
    

    这里发生了非常奇怪的行为。你可以用那里的任何日期 StruthOtoDATE() 函数和该查询将返回表中的所有记录(甚至是将来的某个记录)。文件表明 StruthOtoDATE() 应返回日期时间,该日期时间应为 DATE_SUB() 但显然有问题。

    作为旁注,跑步 SELECT STR_TO_DATE('10/06/2010 23:59:59', '%m/%d/%Y %T') 返回第一个查询的准确输入, 2010-10-06 23:59:59 . 另外,如果将 StruthOtoDATE() 函数在问题查询中使用 TIMESTAMP() 函数或A CAST(STR_TO_DATE() AS DATETIME) ,然后按预期返回结果。但这真的有必要吗?

    我想我错过了一些东西。有人能发光吗?

    更新

    这绝对像个虫子。在版本5.1.36上:

    -- interval of month or day does not work:
    SELECT '1999-04-01 23:34:12' > DATE_SUB(STR_TO_DATE('09/06/2010 23:59:59', '%m/%d/%Y %T'), INTERVAL 1 MONTH);
    --->  1   (incorrect)
    -- using 720 hours (30 days) works:
    SELECT '1999-04-01 23:34:12' > DATE_SUB(STR_TO_DATE('09/06/2010 23:59:59', '%m/%d/%Y %T'), INTERVAL 720 HOUR);
    --->  0
    -- wrapping in TIMESTAMP( ) works:
    SELECT '1999-04-01 23:34:12' > DATE_SUB(TIMESTAMP(STR_TO_DATE('09/06/2010 23:59:59', '%m/%d/%Y %T')), INTERVAL 1 MONTH);
    --->  0
    

    在版本5.0.51A-LOG上,所有工作都按预期进行:

    SELECT '1999-04-01 23:34:12' > DATE_SUB(STR_TO_DATE('09/06/2010 23:59:59', '%m/%d/%Y %T'), INTERVAL 1 MONTH);
    --->  0  
    SELECT '1999-04-01 23:34:12' > DATE_SUB(STR_TO_DATE('09/06/2010 23:59:59', '%m/%d/%Y %T'), INTERVAL 720 HOUR);
    --->  0
    SELECT '1999-04-01 23:34:12' > DATE_SUB(TIMESTAMP(STR_TO_DATE('09/06/2010 23:59:59', '%m/%d/%Y %T')), INTERVAL 1 MONTH);
    --->  0
    
    1 回复  |  直到 14 年前
        1
  •  2
  •   Quassnoi    14 年前

    这真的很奇怪,好像是个虫子。

    我把它归结为:

    SELECT  '0000-00-00 00:00:20' > STR_TO_DATE('10/06/2010 23:59:59', '%m/%d/%Y %T') - INTERVAL 1 MONTH,
            '0000-00-00 00:00:21' > STR_TO_DATE('10/06/2010 23:59:59', '%m/%d/%Y %T') - INTERVAL 1 MONTH
    

    也就是说,将第二个表达式中的年份与第一个表达式中的秒进行比较。

    可能有点奇怪 DATE INTEGER 介于两者之间。

    请注意,如果您添加 + INTERVAL 0 SECONDS 将表达式转换为 DATETIME 而且效果很好。

    我会把它作为一个bug发布到 MySQL .

    更新:

    此已作为 bug 一周前发布了一个补丁来修复它。