选择在一个给定的日期创建的所有记录

时间:2022-06-30 09:27:45

Given a table orders:

给定一个表的订单:

+-----+---------+-------------------------+
| id  |  price  |         created_at      |
+-----+---------+-------------------------+
|  1  |  16.50  | 2017-02-28 12:52:00.824 |
|  2  |  22.00  | 2017-10-03 15:12:39.107 |
|  3  |  50.00  | 2017-12-03 12:54:42.658 |
|  4  |  12.00  | 2018-01-02 07:21:47.808 |
|  .  |   .     |             .           |
|  .  |   .     |             .           |
|  .  |   .     |             .           |
+-----+---------+-------------------------+

and current date:

当前日期:

+---------------------+
| NOW()               |
+---------------------+
| 2018-01-03 10:33:14 |
+---------------------+

I'd like to select all records that were created on current day any months ago. So for above data my query should return:

我想选择在任何一个月前的当天创建的所有记录。因此,对于以上数据,我的查询应该返回:

+-----+---------+-------------------------+
| id  |  price  |         created_at      |
+-----+---------+-------------------------+
|  2  |  22.00  | 2017-10-03 15:12:39.107 |
|  3  |  50.00  | 2017-12-03 12:54:42.658 |
+-----+---------+-------------------------+

But there are some edge cases for the last day of month:

但是在这个月的最后一天,也有一些边缘病例:

  • if it's 31-days month, it's trivial
  • 如果是一个月31天,那是微不足道的
  • if it's 30-days month, the query should return all records created on 30th and 31st day of month
  • 如果是30天月,查询应该返回在30天和31天创建的所有记录
  • if it's February in a leap year, the query should return all records created on 29th, 30th and 31st day of month
  • 如果是闰年的2月,查询应该返回在29、30和31日创建的所有记录
  • if it's February in a normal year, the query should return all records created on 28th, 29th, 30th and 31st day of month
  • 如果是正常年份的2月,查询应该返回在28、29、30和31日创建的所有记录

What I have tried is something like this:

我试过的是这样的:

SELECT * FROM orders
JOIN (
  SELECT id, PERIOD_DIFF(
    DATE_FORMAT(NOW(), "%Y%m"),
    DATE_FORMAT(created_at, "%Y%m")
  ) AS diff
  FROM orders
) AS periods
ON orders.id = periods.id
WHERE DATEDIFF(created_at + INTERVAL diff MONTH, NOW()) = 0;

But it doesn't cover the edge cases and I believe there is a smarter way (maybe without a subquery) to achieve the expected results.

但它并没有涵盖边缘情况,我相信有一种更聪明的方法(可能没有子查询)来实现预期的结果。


EDIT: To give you more context - what I need is a kind of a loop. I have a cron job scheduled to run once a day at midnight. This job should select all ids of orders that were created on this day any months ago and then refresh some other data associated with those ids. The important part is to refresh this data exactly once every month - that's why the last day of months is so crucial.

For example, given following creation dates:

例如,给定以下创建日期:

DATES = [
  2015-05-30, 2016-02-29, 2016-10-03,
  2016-12-31, 2017-05-28, 2018-01-03
]

+---------------+------------------------------------+
|     NOW()     |         SHOULD BE INCLUDED         |
+---------------+------------------------------------+
|  2018-01-03   | 2016-10-03, 2018-01-03             |
|  2018-02-28   | 2016-02-29, 2016-12-31, 2017-05-28 |
|  2018-04-30   | 2015-05-30, 2016-12-31             |
|  2018-10-31   | 2016-12-31                         |
+---------------+------------------------------------+

3 个解决方案

#1


1  

Can I suggest a slight simplification Walerian?

我能建议一个稍微简化一下的Walerian式吗?

SELECT 
    *

FROM 
    orders

WHERE 
    (
        DAYOFMONTH(created_at) = DAYOFMONTH( NOW() ) --monthdays that match
    )
    OR
    (
        (  DAYOFMONTH(  LAST_DAY( NOW() )  ) = DAYOFMONTH( NOW() )  ) --base date is end of month
        AND
        (  DAYOFMONTH(created_at) > DAYOFMONTH( NOW() )  ) --target monthdays are beyond base monthday
    )

Incidentally I don't have a MySQL environment, so I'm just taking it on trust that these are the correct functions in MySQL.

顺便说一句,我没有MySQL环境,所以我相信这些是MySQL中正确的函数。

#2


1  

Use DAYOFMONTH() function to compare the day of the NOW() and the created_at. Like this:

使用DAYOFMONTH()函数比较NOW()和created_at的日期。是这样的:

SELECT * FROM ORDERS
WHERE (DAYOFMONTH(NOW() < LAST_DAY(NOW()) -- if not last day of month 
        AND DAYOFMONTH(created_at) = DAYOFMONTH(NOW())
OR (LAST_DAY(NOW()) = DAYOFMONTH(NOW()) -- if last day of month
     AND DAYOFMONTH(NOW()) BETWEEN DAYOFMONTH(created_at) AND LAST_DAY(created_at)) -- 

#3


0  

Inspired by suresubs's answer, I figured out how the query should look like.

受到suresubs回答的启发,我想出了这个查询应该是什么样子。

SELECT * FROM orders
-- (1)
WHERE (DAYOFMONTH(NOW) < DAYOFMONTH(LAST_DAY(NOW()))
  AND DAYOFMONTH(created_at) = DAYOFMONTH(NOW()))
-- (2)
OR (DAYOFMONTH(LAST_DAY(NOW())) = DAYOFMONTH(NOW())
  AND DAYOFMONTH(created_at) BETWEEN DAYOFMONTH(NOW()) AND DAYOFMONTH(LAST_DAY(created_at)));

It's using DAYOFMONTH() and LAST_DAY() functions and it's divided into two cases:

它使用DAYOFMONTH()和LAST_DAY()函数,分为两种情况:

  1. Today is not the last day of current month.
  2. 今天不是这个月的最后一天。
  3. Today is the last day of current month.
  4. 今天是这个月的最后一天。

#1


1  

Can I suggest a slight simplification Walerian?

我能建议一个稍微简化一下的Walerian式吗?

SELECT 
    *

FROM 
    orders

WHERE 
    (
        DAYOFMONTH(created_at) = DAYOFMONTH( NOW() ) --monthdays that match
    )
    OR
    (
        (  DAYOFMONTH(  LAST_DAY( NOW() )  ) = DAYOFMONTH( NOW() )  ) --base date is end of month
        AND
        (  DAYOFMONTH(created_at) > DAYOFMONTH( NOW() )  ) --target monthdays are beyond base monthday
    )

Incidentally I don't have a MySQL environment, so I'm just taking it on trust that these are the correct functions in MySQL.

顺便说一句,我没有MySQL环境,所以我相信这些是MySQL中正确的函数。

#2


1  

Use DAYOFMONTH() function to compare the day of the NOW() and the created_at. Like this:

使用DAYOFMONTH()函数比较NOW()和created_at的日期。是这样的:

SELECT * FROM ORDERS
WHERE (DAYOFMONTH(NOW() < LAST_DAY(NOW()) -- if not last day of month 
        AND DAYOFMONTH(created_at) = DAYOFMONTH(NOW())
OR (LAST_DAY(NOW()) = DAYOFMONTH(NOW()) -- if last day of month
     AND DAYOFMONTH(NOW()) BETWEEN DAYOFMONTH(created_at) AND LAST_DAY(created_at)) -- 

#3


0  

Inspired by suresubs's answer, I figured out how the query should look like.

受到suresubs回答的启发,我想出了这个查询应该是什么样子。

SELECT * FROM orders
-- (1)
WHERE (DAYOFMONTH(NOW) < DAYOFMONTH(LAST_DAY(NOW()))
  AND DAYOFMONTH(created_at) = DAYOFMONTH(NOW()))
-- (2)
OR (DAYOFMONTH(LAST_DAY(NOW())) = DAYOFMONTH(NOW())
  AND DAYOFMONTH(created_at) BETWEEN DAYOFMONTH(NOW()) AND DAYOFMONTH(LAST_DAY(created_at)));

It's using DAYOFMONTH() and LAST_DAY() functions and it's divided into two cases:

它使用DAYOFMONTH()和LAST_DAY()函数,分为两种情况:

  1. Today is not the last day of current month.
  2. 今天不是这个月的最后一天。
  3. Today is the last day of current month.
  4. 今天是这个月的最后一天。