mySQL中的PostgreSQL date_trunc

时间:2011-04-04 16:18:56

标签: mysql postgresql

最近,我已经熟悉了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中重新创建这样的规定。所以,我在一天结束时的问题是,是否可以通过尝试复制date_trunc(以及如何)在mySQL中完成这种类型的查询,或者我是否需要以不同的方式开始查看这些类型的查询以使它们工作在mySQL中(以及如何做到这一点的建议)?

3 个答案:

答案 0 :(得分:25)

  

提取函数似乎很有用,我找到的日期函数解决了我的一些问题,但有没有办法复制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在处理日期范围方面确实很差,即使字段已编入索引。如果你不小心的话,你可能最终会进行全表扫描。

答案 1 :(得分:4)

派对迟到了,但是......

如果您知道间隔,有一种方法可以获得截断日期。例如,如果时间间隔为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())

答案 2 :(得分:1)

这里是一个函数,它使用@Charles上面推荐的DATE_TRUNC mysql函数来模仿postgres的DATE_FORMAT契约。

DROP FUNCTION IF EXISTS DATE_TRUNC;
CREATE FUNCTION DATE_TRUNC(
  in_granularity ENUM('hour', 'day', 'month', 'year'),
  in_datetime datetime(6)
)
RETURNS datetime(6)
DETERMINISTIC
BEGIN
  IF (in_granularity = 'hour') THEN
    RETURN DATE_FORMAT(in_datetime, '%Y-%m-%d %H:00:00.0000');
  END IF;
  IF (in_granularity = 'day') THEN
    RETURN DATE_FORMAT(in_datetime, '%Y-%m-%d 00:00:00.0000');
  END IF;
  IF (in_granularity = 'month') THEN
    RETURN DATE_FORMAT(in_datetime, '%Y-%m-01 00:00:00.0000');
  END IF;
  IF (in_granularity = 'year') THEN
    RETURN DATE_FORMAT(in_datetime, '%Y-01-01 00:00:00.0000');
  END IF;
END;