mySQL SELECT upcoming birthdays

前端 未结 17 583
我寻月下人不归
我寻月下人不归 2020-12-03 11:17

I\'m trying to write a query to select users of a database whose birthdays are in the next 7 days.

I\'ve done a lot of research but I can\'t come up with a working s

相关标签:
17条回答
  • 2020-12-03 11:51

    To get all birthdays in next 7 days, add the year difference between the date of birth and today to the date of birth and then find if it falls within next seven days.

    SELECT * 
    FROM  persons 
    WHERE  DATE_ADD(birthday, 
                    INTERVAL YEAR(CURDATE())-YEAR(birthday)
                             + IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(birthday),1,0)
                    YEAR)  
                BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY);
    

    If you want to exclude today's birthdays just change > to >=

    SELECT * 
    FROM  persons 
    WHERE  DATE_ADD(birthday, 
                    INTERVAL YEAR(CURDATE())-YEAR(birthday)
                             + IF(DAYOFYEAR(CURDATE()) >= DAYOFYEAR(birthday),1,0)
                    YEAR)  
                BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY);
    
    -- Same as above query with another way to exclude today's birthdays 
    SELECT * 
    FROM  persons 
    WHERE  DATE_ADD(birthday, 
                    INTERVAL YEAR(CURDATE())-YEAR(birthday)
                             + IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(birthday),1,0)
                    YEAR) 
                BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
         AND DATE_ADD(birthday, INTERVAL YEAR(CURDATE())-YEAR(birthday) YEAR) <> CURDATE();
    
    
    -- Same as above query with another way to exclude today's birthdays 
    SELECT * 
    FROM  persons 
    WHERE  DATE_ADD(birthday, 
                    INTERVAL YEAR(CURDATE())-YEAR(birthday)
                             + IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(birthday),1,0)
                    YEAR) 
                BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
         AND (MONTH(birthday) <> MONTH(CURDATE()) OR DAY(birthday) <> DAY(CURDATE()));
    

    Here is a DEMO of all queries

    0 讨论(0)
  • 2020-12-03 11:53

    Building on Lobo's answer to tackle leap years

    SELECT * FROM users
    WHERE DATE_ADD(dob,INTERVAL YEAR(CURDATE())-YEAR(dob)
      + IF(MONTH(CURDATE()) > MONTH(dob), 1,
         IF(MONTH(CURDATE()) = MONTH(dob) AND DAY(CURDATE()) > DAY(dob), 1, 0))
           YEAR)
            BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
    
    0 讨论(0)
  • 2020-12-03 11:54

    This is my solution. It also works if date of birth is January 1st and today's date is December 31.

    SELECT `id`, `name`, `dateofbirth`,
        DATE_ADD(
            dateofbirth, 
            INTERVAL IF(DAYOFYEAR(dateofbirth) >= DAYOFYEAR(CURDATE()),
                YEAR(CURDATE())-YEAR(dateofbirth),
                YEAR(CURDATE())-YEAR(dateofbirth)+1
            ) YEAR
        ) AS `next_birthday`
    FROM `user` 
    WHERE 
        `dateofbirth` IS NOT NULL
    HAVING 
        `next_birthday` BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
    ORDER BY `next_birthday`
    LIMIT 1000;
    
    0 讨论(0)
  • 2020-12-03 11:54

    I found this code to work really well:

    DATE_ADD(user_birthdate, INTERVAL YEAR(FROM_DAYS(DATEDIFF(CURDATE(), user_birthdate)-1)) + 1 YEAR) AS next_birthday 
    

    it actually really simple, it calculate the person age, then the current's year birthday and then add 1 year.

    it based on the answer of Robert Eisele which you may find here: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

    p.s.

    with this solution you might fetch people who had a birthday yesterday (that's because the -1 in the FROM_DAYS calculation, but it is needed because of the leap years). this shouldn't consider you too much since you only want 7 days a head so you should just add the following condition:

    HAVING next_birthday BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY) 
    
    0 讨论(0)
  • 2020-12-03 11:54

    While trying to get the list who have their b'days upcoming in a range of time, we can run in to couple of issues.

    When there is a leap year, then there is a chance that the condition you have fails to handle the case of leap years. Next problem could be like today is 2016-12-30 and you need b'days for next 7 days. So the end of the period is in year 2017. Some condition fail in this case. These are very important test cases.

    Most of the fixed in this thread are using the DAYOFYEAR() which fails when you are on a leap year.

    eg.

    DAYOFYEAR('2016-03-01 00:00:00') is 61.
    DAYOFYEAR('2015-03-01 00:00:00') is 60

    Simplest and most easy to understand way is this.

    1. Calculate the next upcoming b'day for a user.
    2. Then check if the day comes in our range.

    This works on leap years and also the range of dates span in two years.

    SELECT  * 
    FROM    `PERSONS` 
    WHERE  
        /* 
           Here we calculate the next coming b'day for user 
           and check if it is between our span 
        */
        CONCAT(IF( 
                CONCAT( YEAR(CURDATE()), substring(`BIRTHDAY`, 5, length(`BIRTHDAY`))) < CURDATE(), 
                YEAR(CURDATE()) + 1, /* Adds an year if already past */
                YEAR(CURDATE())  /* Use this year if it is upcoming */
             ), substring(`BIRTHDAY`, 5, length(`BIRTHDAY`))) 
        BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL @tot DAY)
    

    PS: Also it is the best solution if you want to order these on the basis of the b'days. You just need to add this as a field.

    0 讨论(0)
  • 2020-12-03 11:55

    This is optimized solution for leap year problem

    SELECT * 
    FROM  persons 
    WHERE DATE_FORMAT( CONCAT(YEAR(CURDATE()),'-',DATE_FORMAT(birth_date, '%m-%d') ), '%Y-%m-%d')
         BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY)
    
    0 讨论(0)
提交回复
热议问题