MySQL 获取上个月的具体日期

MySQL get specific date of last month

我想 select 自上个月 20th 以来的所有行。

我知道我可以使用 SELECT NOW() - INTERVAL 1 MONTH select 一个月前的日期,但我如何设置那个月的特定日期?

今天是 March 28th,我想 select 所有比 February 20th 新的行。

即使我可以直接设置日期,如果查询的日期是 31st 那对 2 月不起作用,而应该 select 该月的最后一天。

注意:20th 只是一个示例,该值是在代码的其他地方动态生成的。

一些例子:

Day: 20th each month
Now: March 28th | Query: February 20th
Now: May 28th | Query: April 20th
Day: 31st each month
Now: March 28th | Query: February 28th // we select last day instead of 31st
Now: May 28th | Query: April 30th // we select last day instead of 31st

完整的查询类似于 SELECT * FROM sales WHERE date > SET_DAY(20, NOW() - INTERVAL 1 MONTH)

那么,我可以将 SET_DAY 替换为什么(也适用于较短的月份)?

一个非常常见的用例是计费周期,您想要select当前计费周期内的所有数据。

好吧,我相信这可以解决问题

select now()
- interval 1 month
- interval(
   day(now())
   - least(
      20,
      day(last_day(now() - interval 1 month))
     )
  ) day

假设您在客户端中有一个参数是目标天数,并且您想在 sql 中验证它(确保您想出上个月内的一天),而不是客户,我会做:

least(
    date(date_format(current_date - interval 1 month, '%Y-%m-01')) + interval ? - 1 day,
    date(date_format(current_date, '%Y-%m-01')) - interval 1 day
)

一个警告:current_date 将是连接时区中的当前日期,由客户端控制;如果我知道我希望当天在哪个时区,我更愿意始终明确,例如:

date(convert_tz(utc_timestamp(), '+00:00', 'America/Los_Angeles'))

而不只是 current_date(两个地方)。

我刚刚意识到我的问题并没有包括所有情况。如果最后一个账单日在本月内,则应计算本月的 20 日(而不是之前的)。

根据@ysth 的回答,我在本月的 select 20 日添加了一个 IF(如果我们通过了),否则上个月:

IF(DAY(current_date) >= 20, 
   date(date_format(current_date, '%Y-%m-01')) + interval 20 - 1 day,
    least(
        date(date_format(current_date - interval 1 month, '%Y-%m-01')) + interval 20 - 1 day,
        date(date_format(current_date, '%Y-%m-01')) - interval 1 day
    )
);