PostgreSQL在mySQL中的日期截断

yc0p9oo0  于 2023-01-16  发布在  Mysql
关注(0)|答案(4)|浏览(191)

最近,我开始熟悉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中工作(以及关于如何做到这一点的建议)?

hwamh0ep

hwamh0ep1#

extract函数看起来很有用,我发现date函数解决了我的一些问题,但是有什么方法可以复制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在处理日期范围方面真的很差,即使字段被索引了,如果不小心的话,你可能会以一个完整的表扫描结束。

vc6uscn9

vc6uscn92#

派对迟到了但是。
如果您知道间隔,有一种方法可以获取截断日期。例如,如果间隔为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())
klr1opcd

klr1opcd3#

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

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;
7cwmlq89

7cwmlq894#

以下是一些最常见的Redshift/Postgres date_trunc表达式的MySQL等效表达式,使用日期算法:

select 
null

-- RS date_trunc('hour', now()) = '2023-01-13 17:00:00.000 +0100'
,date_add(date(now()), interval hour(now()) hour) as trunc_hour

-- RS date_trunc('week', now()) = '2023-01-09 00:00:00.000 +0100'
,date_sub(cast(date(now()) as datetime), interval weekday(now()) day) as trunc_week

-- RS date_trunc('month', now()) = '2023-01-01 00:00:00.000 +0100'
,date_add(cast(makedate(year(now()), 1) as datetime), interval month(now())-1 month) as trunc_month

-- RS date_trunc('year', now()) = '2023-01-01 00:00:00.000 +0100'
,cast(makedate(year(now()), 1) as datetime) as trunc_year

相关问题