PostgreSQL date_trunc в mySQL

В последнее время я знаком с PostgreSQL (с использованием 8.2) и нашел функцию date_trunc чрезвычайно полезной для удобного совпадения временных меток между определенными днями/месяцами/и т.д. Я считаю, что реальная полезность функции исходит из того, что она сохраняет вывод в формате метки времени.

Мне пришлось переключиться на mySQL (5.0) и найти некоторые функции даты, которых нет в сравнении. Функция извлечения кажется полезной, и функция даты, которую я нашел, решает некоторые из моих проблем, но есть ли способ репликации PostgreSQL date_trunc?

Ниже приведен пример того, как я использовал date_trunc для сопоставления запрошенных временных меток только за последние 4 месяца, включая текущий месяц, но только если неделя уже прошла в этом месяце:

WHERE date_trunc('month', QUERY_DATE) BETWEEN 
    date_trunc('month', now()) - INTERVAL '4 MONTH' AND 
    date_trunc('month', now() - INTERVAL '1 WEEK')

Я не знаю, как воссоздать такую ​​оговорку в mySQL. Итак, мой вопрос в конце дня заключается в том, может ли этот тип запроса быть выполнен в mySQL, попробовав replicate date_trunc (и как) или мне нужно начинать смотреть на эти типы запросов по-другому, чтобы заставить их работать в mySQL (и предложения о том, как это сделать)?

Ответ 1

Функция extract кажется полезной, и функция даты, которую я нашел, решает некоторые из моих проблем, но есть ли способ репликации PostgreSQL date_trunc?

Действительно, EXTRACT выглядит так, что это будет самое близкое соответствие для этого конкретного случая.

Ваш исходный код в PG:

WHERE date_trunc('month', QUERY_DATE) BETWEEN 
    date_trunc('month', now()) - INTERVAL '4 MONTH' AND 
    date_trunc('month', now() - INTERVAL '1 WEEK')

Использование EXTRACT:

WHERE EXTRACT(YEAR_MONTH FROM QUERY_DATE)
      BETWEEN
          EXTRACT(YEAR_MONTH FROM NOW() - INTERVAL 4 MONTH)
      AND
          EXTRACT(YEAR_MONTH FROM NOW() - INTERVAL 1 WEEK)

В то время как он должен быть функционально идентичным, это фактически приводит в действие даты в строку YYYYMM перед выполнением сравнения.

Другим вариантом будет использование DATE_FORMAT для восстановления строки даты и ее начала в начале месяца:

WHERE DATE_FORMAT(QUERY_DATE, '%Y-%m-01')
      BETWEEN
          DATE_FORMAT(NOW() - INTERVAL 4 MONTH, '%Y-%m-01')
      AND
          DATE_FORMAT(NOW() - INTERVAL 1 WEEK, '%Y-%m-01')

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

Ответ 2

поздно на вечеринку, но...

существует способ получить усеченную дату, если вы знаете интервал. Например, если интервал MONTH, вы можете получить сегодняшнюю дату (now()), усеченную до месяца, используя следующее:

select date_add('1900-01-01', interval TIMESTAMPDIFF(MONTH, '1900-01-01', now()) MONTH);

Учитывая вышеизложенное, можно создать функцию, которая также будет следить за другими интервалами:

DELIMITER //
create function date_trunc(vInterval varchar(7), vDate timestamp)
returns timestamp
begin
    declare toReturn timestamp;

    if vInterval = 'year' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(YEAR, '1900-01-01', vDate) YEAR);
    elseif vInterval = 'quarter' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(QUARTER, '1900-01-01', vDate) QUARTER);
    elseif vInterval = 'month' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(MONTH, '1900-01-01', vDate) MONTH);
    elseif vInterval = 'week' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(WEEK, '1900-01-01', vDate) WEEK);
    elseif vInterval = 'day' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(DAY, '1900-01-01', vDate) DAY);
    elseif vInterval = 'hour' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(HOUR, '1900-01-01', vDate) HOUR);
    elseif vInterval = 'minute' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(MINUTE, '1900-01-01', vDate) MINUTE);
    END IF;

    return toReturn;
end//
DELIMITER ;

Используйте его так:

select date_trunc('quarter', now())