【问题标题】:mysql birthday reminder, leap yearmysql生日提醒,闰年
【发布时间】:2011-01-14 12:41:08
【问题描述】:

我正在尝试整理一个结果集,该结果集提供了按即将到来的生日排序的 5 个最接近的用户。在闰年开始之前,这非常有效。例如:

  • 5 月 15 日 - 还剩 96 天
  • 5 月 15 日 - 还剩 97 天

最高的结果是 1987 年出生,最低的是 1988 年。 u_birth 存储为 yyyy-mm-dd。 有没有一种简单的方法可以对这个问题进行排序,而不必重写整个查询?

SELECT u_birth, IF( DAYOFYEAR( u_birth ) >= DAYOFYEAR( NOW() ), 
          DAYOFYEAR( u_birth ) - DAYOFYEAR( NOW() ), 
          DAYOFYEAR( u_birth ) - DAYOFYEAR( NOW() ) +  
      DAYOFYEAR( CONCAT( YEAR( NOW() ), '-12-31' ) ) 
 )  
 AS distance
FROM (blog_users)
WHERE `s_agehide` = 0
ORDER BY distance ASC
LIMIT 5

此查询取自 mysql 手册并进行了修改:http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#c7489

【问题讨论】:

    标签: mysql leap-year


    【解决方案1】:

    如果您的算法取决于人的出生年份,那么显然存在问题。要解决此问题,请先找到每个人在当前日期之后的下一个生日,然后计算该日期与现在之间的差异。

    SELECT u_birth, DATEDIFF(next_birthday, NOW()) AS distance FROM (
        SELECT *, ADDDATE(birthday, INTERVAL birthday < DATE(NOW()) YEAR) AS next_birthday
        FROM (
            SELECT *, ADDDATE(u_birth, INTERVAL YEAR(NOW()) - YEAR(u_birth) YEAR) AS birthday
            FROM blog_users
            WHERE s_agehide = 0
        ) AS T1
    ) AS T2
    ORDER BY distance ASC
    LIMIT 5
    

    结果:

    '1992-02-29', 20
    '1993-03-01', 21
    '1987-05-15', 96
    '1988-05-15', 96
    '1988-09-18', 222
    

    测试数据:

    CREATE TABLE blog_users (u_birth NVARCHAR(100) NOT NULL, s_agehide INT NOT NULL);
    INSERT INTO blog_users (u_birth, s_agehide) VALUES
    ('1987-05-15', 0),
    ('1988-05-15', 0),
    ('1988-09-20', 0),
    ('2000-01-02', 0),
    ('2000-01-03', 1),
    ('1988-09-19', 0),
    ('1988-09-18', 0),
    ('1992-02-29', 0),
    ('1993-03-01', 0);
    

    请注意,闰日出生的人被假定为非闰年的 2 月 28 日生日。

    此外,您的查询不包括用户的用户 ID。我想你可能也想添加这个。

    【讨论】:

    • 谢谢!我去看看,给我几分钟试试=)
    • @tired:请注意,我做了一个小改动,让今天生日的所有人的距离都为 0,而不是距离 365。我将 NOW() 更改为 DATE(NOW())。
    • 它按预期工作,但是我有一个后续问题:如何从表中检索其他行?我已经尝试了所有三个选择,但没有运气,可以说我也想检索 s_agehide。感谢大家的帮助!
    • @tired:我假设你的意思是列,而不是行?我稍微重写了查询,以便更容易添加列。获取新版本,然后将您想要的任何额外列添加到最外层(最顶层)的选择子句中。
    • 有效! =) 非常感谢您的复杂查询,您为我节省了时间哈哈,再次感谢!
    【解决方案2】:
    SELECT
        CONCAT(
            YEAR(CURRENT_DATE()),
            '-',
            DATE_FORMAT((birthDate),
                '%m-%d'
            )
        ),
        fullName
    FROM
        employees
    WHERE
        birthDate != 0
    AND(
        CONCAT(
            YEAR(CURRENT_DATE())+ 1,
            '-',
            DATE_FORMAT((birthDate),
                '%m-%d'
            )
        )BETWEEN CURRENT_DATE()
        AND DATE_ADD(
            CURRENT_DATE(),
            INTERVAL 21 DAY
        )
        OR CONCAT(
            YEAR(CURRENT_DATE()),
            '-',
            DATE_FORMAT((birthDate),
                '%m-%d'
            )
        )BETWEEN CURRENT_DATE()
        AND DATE_ADD(
            CURRENT_DATE(),
            INTERVAL 21 DAY
        )
    )
    

    ps:birthDate 是我存储员工出生日期的列。 employees 是表名。

    【讨论】:

      【解决方案3】:

      不要使用dayofyear,因为闰年​​ 2 月 29 日之后的任何内容都会比平时晚一天。相反,提取月份和日期并将它们与今天的年份连接在一起。然后进行比较。

      像这样:

      SELECT u_birth, 
        IF(DATE(CONCAT(YEAR(NOW()),'-',MONTH(u_birth),'-',DAY(u-birth))) >= DATE(NOW()),
      ...
      

      预计到达时间:

      为了不必重写将出生日期转换为生日的表达式,我将其粘贴在变量中。我建议您编写一个进行转换的函数,以便您可以直接在查询中使用它。

      SET @birthday= SELECT DATE(CONCAT(YEAR(NOW()),'-',MONTH(u_birth),'-',DAY(u-birth))) FROM users WHERE user_id=x; //obviously only good for one value, but use the example for the calculation
      
      SELECT u_birth, 
             IF(DATE(@birthday)>=DATE(NOW()), 
                DATEDIFF(DATE_ADD(@birthday, INTERVAL 1 YEAR),NOW()), 
                DATEDIFF(NOW(),@birthday)
             ) as days
      FROM users WHERE user_id=x;
      

      【讨论】:

      • 我尝试用您展示的示例替换所有 dayofyear,是的,闰年问题消失了,但价值和排序完全关闭。你能告诉我整个重写的查询吗?
      【解决方案4】:

      也许有人会从这种平静的代码中得到启发。

      在我的情况下它工作得很好,但我认为有很多日期计算......

      SELECT CONCAT(YEAR(CURRENT_DATE()),'-',DATE_FORMAT( FROM_UNIXTIME(date_of_birth), '%m-%d' )), fe_users.* 
      FROM `fe_users`
      WHERE `date_of_birth` != 0 AND (
           CONCAT(YEAR(CURRENT_DATE())+1,'-',DATE_FORMAT( FROM_UNIXTIME(date_of_birth), '%m-%d' )) BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY)
           OR
           CONCAT(YEAR(CURRENT_DATE()),'-',DATE_FORMAT( FROM_UNIXTIME(date_of_birth), '%m-%d' )) BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY)
      )
      

      通过这种 SQL 代码的和平,您将获得表 fe_users 的所有用户,其 date_of_birth(保存为 unix-timestamp)将在接下来的 7 天内。您可以通过更改 date_add() 函数使用的时间间隔轻松地将其延长至 21 天。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-14
        • 1970-01-01
        相关资源
        最近更新 更多