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())