Поиск по дате

Детские граблиВот уж не подумал бы, что на совершенно тривиальных запросах к MySQL можно наступить на детские грабли.

Я не люблю обновлять MySQL ни на своей машине, ни на сервере. Каждый раз гадаешь: «понадобится бэкап или или нет?» Поэтому имеет место некоторая несогласованность версий, на которую я не слишком сильно обращал внимание. До сегодняшнего вечера. Итак у меня в наличии на домашней машине MySQL 5.1.22-rc-community, win32. На сервере соответственно MySQL 5.0.45 из бокса CentOS 5.

Самая обычная таблица в БД, с самым обычным полем created типа DATETIME.

Однако запрос

SELECT
    COUNT(*) AS `count`
FROM
    `offers` AS `Offer`
WHERE
    `Offer`.`supplier_id` = 3 AND
    DATE(`Offer`.`created`) = '2009-03-12'

работает на них совершенно по-разному!

На домашней машине все, как ожидается, возвращается количество записей за 12-е число. На сервере — 0 записей. После некоторого яндексения в гугле, выяснилось, что на эти грабли, конечно же, наступал не я один и, в зависимости от версии, вернее, от релиза, обработка такого условия работает по-разному.

На домашней машине у поля DATETIME обрезается часть, содержащая время. На сервере наоборот, к выражению для сравнения добавляется ‘ 00:00:00′. :-/ Но отчего тогда не срабатывает функция DATE() все равно непонятно, это встроенный оптимизатор MySQL ее оптимизирует нафиг?

Много английских букв на близкую тему: http://bugs.mysql.com/bug.php?id=28929.

В соответствии с советами из мануала MySQL переделал запрос так:

SELECT
    COUNT(*) AS `count`
FROM
    `offers` AS `Offer`
WHERE
    `Offer`.`supplier_id` = 3 AND
    CAST(`Offer`.`created` AS DATE) = '2009-03-12'

все равно не работает! Единственный заработавший вариант выглядит так:

SELECT
    COUNT(*) AS `count`
FROM
    `offers` AS `Offer`
WHERE
    `Offer`.`supplier_id` = 3 AND
    SUBSTR(`Offer`.`created`,1,10) = '2009-03-12'

некрасиво, но других идей нет. Использовать BETWEEN совсем не хочется.

Самое неприятное в том, что заранее точно сказать будет-ли работать нормальное условие с DATE() на каком-то сервере нельзя. Можно только предположить.

Оставить SUBSTR навечно или наваять какой-нибудь переключатель в зависимости от настроек? Написать тест и по его результатам указыватьчто-то типа

Configure::write('App.Database.MySQLDateTimeExtractor', 'SUBSTR'); // or 'DATE'

В общем, надо повнимательнее к выборке дат.

Related Posts with Thumbnails
13.03.2009 • Метки: , , • Рубрики: MySQL
blog comments powered by Disqus