在MySql中查找n天内是否会出现周年纪念日

时间:2010-05-20 14:39:56

标签: mysql datetime

我有一张周年纪念日的桌子。我想要一个查询,它会在接下来的10天内返回一系列纪念日。例如:

birthdate
---------
1965-10-10
1982-05-25


SELECT birthdate FROM Anniversaries WHERE mystical_magical_mumbo_jumbo <= 10

+------------+
| birthdate  |
+------------+
| 1982-05-25 |
+------------+
1 row in set (0.01 sec)

我想以x <= 10的形式保存查询,因为我会在查询的其他部分使用该数字10,如果我将其设置为变量,我可以在任何地方更改它通过更改变量,而不必重新编写查询。

7 个答案:

答案 0 :(得分:7)

正如其他人所说,你需要忽略比较中的年份。 DAYOFYEAR()函数是一种方法。

这是我头脑中的快速解决方案。它将在接下来的10天内返回所有生日,即使是12月下旬和生日是明年。

它没有正确处理闰年,因此如果今年是闰年并且该人不是在闰年出生,反之亦然,那么3月初生日将会停止1天。闰年也将导致1月初的生日有时在12月下旬出现休息一天。如果有人想添加闰年修正,请随意:)

SELECT birthdate 
FROM Anniversaries 
WHERE dayofyear(birthdate) - dayofyear(curdate()) between 0 and 10 
or dayofyear(birthdate) + 365 - dayofyear(curdate()) between 0 and 10;

答案 1 :(得分:1)

试试这个

SELECT birthdate FROM Anniversaries 
WHERE DATEDIFF(CURTIME(),birthdate) >= 0 
AND DATEDIFF(CURTIME(),birthdate) <= 10 

选中此项以获取参考MySQL DATEDIFF

DATEDIFF(表达式1,表达式2)

DATEDIFF()返回expr1 - expr2,表示为从一个日期到另一个日期的天数值。 expr1和expr2是日期或日期和时间表达式。在计算中仅使用值的日期部分。

的MySQL&GT; SELECT DATEDIFF('2007-12-31 23:59:59','2007-12-30');          - &GT; 1

的MySQL&GT; SELECT DATEDIFF('2010-11-30 23:59:59','2010-12-31');          - &GT; -31

答案 2 :(得分:1)

我们想要实现的是在最近的日期范围内发生的周年纪念清单。 为实现这一目标并适应翻转,我们需要生成一份涵盖日期范围的所有周年纪念日清单。 我使用的解决方案产生了去年,今年和明年的周年纪念记录 并仅输出属于给定日期范围内的那些记录。联合查询如下所示:

SELECT Date_Add(birth_date,INTERVAL (Year(now())-Year(birth_date)-1) YEAR) as dt,  
FROM Anniversaries 
WHERE Date_Add(birth_date,INTERVAL (Year(now())-Year(Date)-1) YEAR) 
BETWEEN Date_sub(now(), INTERVAL 7 Day) AND Date_add(now(), INTERVAL 21 Day) 
UNION
SELECT Date_Add(birth_date,INTERVAL (Year(now())-Year(birth_date)) YEAR) as dt,
FROM Anniversaries 
WHERE Date_Add(birth_date,INTERVAL (Year(now())-Year(Date)) YEAR) 
BETWEEN Date_sub(now(), INTERVAL 7 Day) AND Date_add(now(), INTERVAL 21 Day) 
UNION
SELECT Date_Add(birth_date,INTERVAL (Year(now())-Year(birth_date)+1) YEAR) as dt,
FROM Anniversaries 
WHERE Date_Add(birth_date,INTERVAL (Year(now())-Year(Date)+1) YEAR) 
BETWEEN Date_sub(now(), INTERVAL 7 Day) AND Date_add(now(), INTERVAL 21 Day) 
ORDER BY dt

第一个SELECT语句将所有日期递增到去年,并选择属于所提供日期范围的任何项目 下一个SELECT语句将所有日期递增到当前年份,并选择属于所提供日期范围的所有项目 最后一个SELECT语句将所有日期递增到明年,并选择属于所提供日期范围的任何项目 最后,按日期排序。

你有它。这将在给定时期内可靠地选择纪念日。如果需要更长的时间, 可能需要生成其他SELECT语句并将它们与UNION连接。 我修改了我的代码以匹配上面的示例,但自修改以来没有对其进行测试。

答案 3 :(得分:0)

如果您将生日与生日分开存储,则实际上可以使用索引。生日列会有年份和月份,但都会有同一年(例如2000年)。

然后你会这样做你的查询:

SELECT birthdate
FROM Anniversaries
WHERE birthday >= DATE_ADD(MAKEDATE(2000, DAYOFYEAR(CURDATE())), INTERVAL 10 DAYS)

虽然表达式并不完全符合您的要求,但数字10仍位于表达式的右侧。将函数应用于表达式的右侧并仅保留表达式左侧的列允许MySQL使用生日列上的索引(假设您有索引)。

答案 4 :(得分:0)

根据alejandrobog的回答:

SELECT birthdate FROM Anniversaries
WHERE DATEDIFF(MAKEDATE(YEAR(CURRENT_DATE()), DAYOFYEAR(birthdate), CURRENT_DATE()) >= 0
AND   DATEDIFF(MAKEDATE(YEAR(CURRENT_DATE()), DAYOFYEAR(birthdate), CURRENT_DATE()) <= 10

答案 5 :(得分:0)

MAKEDATE()创建一年中的日期和一年中的某一天,因此我可以用它来画出旧年份:

SELECT 
    anniversary
    ,  MAKEDATE( YEAR(NOW()), DAYOFYEAR(anniversary) ) AS thisyear 
FROM Anniversaries;

+-------------+-------------+
| anniversary | thisyear    | 
+-------------+-------------+
| 1978-07-29  | 2010-07-29  |
| 1959-04-17  | 2010-04-17  |
+-------------+-------------+

然后我可以使用DATEDIFF()计算直到(或从那时)的日期:

SELECT 
    anniversary
    , MAKEDATE( YEAR(NOW()), DAYOFYEAR(anniversary) ) AS thisyear
    , DATEDIFF( MAKEDATE(YEAR(NOW()),DAYOFYEAR(anniversary)), NOW()) as days 
FROM Anniversaries;

+-------------+-------------+------+
| anniversary | thisyear    | days | 
+-------------+-------------+------+
| 1978-07-29  | 2010-07-29  |   70 |
| 1959-04-17  | 2010-04-17  |  -33 |
+-------------+-------------+------+

假设NOW()是5/20。


修改,以便上述内容在年度翻转时无效。一种解决方案是添加另一个计算,其中周年纪念日是明年。在这里,我对日期“2010-12-31”进行了硬编码,并在OR子句中使用HAVING来过滤与今年或下一年匹配的天数:

SELECT birth_date
, MAKEDATE(YEAR('2010-12-31'),DAYOFYEAR(birth_date)) as anniversary
,  DATEDIFF( MAKEDATE(YEAR('2010-12-31'),DAYOFYEAR(birth_date)), '2010-12-31') as days
, MAKEDATE(YEAR(NOW())+ 1,DAYOFYEAR(birth_date)) as next_anniversary
, DATEDIFF( MAKEDATE(YEAR(NOW())+ 1,DAYOFYEAR(birth_date)), '2010-12-31') as next_days 
FROM Anniversaries 
HAVING ( ( days <= 25 AND days > 0 ) OR next_days <= 25 );

+------------+-------------+------+------------------+-----------+
| birth_date | anniversary | days | next_anniversary | next_days |
+------------+-------------+------+------------------+-----------+
| 2010-01-23 | 2010-01-23  | -342 | 2011-01-23       |        23 |
| 1975-01-11 | 2010-01-11  | -354 | 2011-01-11       |        11 |
+------------+-------------+------+------------------+-----------+
2 rows in set (0.00 sec)

答案 6 :(得分:0)

     SELECT firstName, lastName, DOB, if( (
     datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date ) ) >=0, (
    datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )), 
    datediff( date( concat( year( current_date ) +1, '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )
)DAYSTOBDAY
    FROM birthinfo
    WHERE (
    if( (
    datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date ) ) >=0, (
    datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )),
    datediff( date( concat( year( current_date ) +1, '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )
    )
    )
    BETWEEN 0
    AND 31

   firstName    lastName    DOB             DAYSTOBDAY
   Michelle     Smith       1979-04-16          17
   Kirsten      Dunst       1982-04-30          31

它远不是一个“好”的答案,它不是很有趣,但是在我的头脑中起作用。实现你想要的。 我创建了一个带有firstname,lastname和DOB的表,当然你可以直接替换它。