MySQL STR_TO_DATE дает неверные результаты? - PullRequest
4 голосов
/ 08 сентября 2010

Я использую MySQL 5.1.49 на Win64.Мы также наблюдаем следующее поведение на машинах 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)

Здесь происходит очень странное поведение.Вы можете использовать любую дату там с функцией STR_TO_DATE(), и этот запрос вернет все записи в таблице (даже в далеком будущем).Документация указывает, что STR_TO_DATE() должен возвращать DATETIME, который должен быть допустимым входным значением для DATE_SUB(), но что-то явно не так.

В качестве примечания, выполнение SELECT STR_TO_DATE('10/06/2010 23:59:59', '%m/%d/%Y %T') возвращает точный вводпервый запрос 2010-10-06 23:59:59.Кроме того, если вы оберните результаты функции STR_TO_DATE() в проблемном запросе функцией TIMESTAMP() или 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 Ответ

2 голосов
/ 08 сентября 2010

Это действительно странно и кажется ошибкой.

Мне удалось свести это к следующему:

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 и работает хорошо.

Я опубликую это как ошибку на MySQL.

Обновление:

Это уже было отправлено как ошибка , и неделю назад был выпущен патч для его исправления.

...